# Help needed with a potential race condition

**URL:** https://clojureverse.org/t/help-needed-with-a-potential-race-condition/11042
**Category:** Troubleshooting
**Tags:** clojure
**Created:** [November 24, 2024, 11:06am UTC](https://clojureverse.org/t/help-needed-with-a-potential-race-condition/11042 "2024-11-24T11:06:12Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![alex314159](https://clojureverse.org/user_avatar/clojureverse.org/alex314159/32/2693_2.png) [@alex314159](https://clojureverse.org/u/alex314159)
#### Post date: [November 24, 2024, 11:06am UTC](https://clojureverse.org/t/help-needed-with-a-potential-race-condition/11042/1 "2024-11-24T11:06:12Z")

</div>

Hello there. I have a trading app connected to Interactive Brokers, and some weird race behaviour that I would welcome some opinion on. I’ve been able to reproduce the error through a stylised example below. I would welcome some help as to what I’m doing wrong, or better understanding why `test-race-2` below is a bad pattern.

Thank you!!

```auto
(def data-deliverer (atom {}))
(def data-container (atom {}))

(defn request-historical-data!
"This is the function that calls Interactive brokers and returns some data, and delivers the promise on completion"
[req-id]
  (swap! data-container assoc req-id [1 2 3 4])
  (deliver (get @data-deliverer req-id) true))

(defn historical-request!
  "Start a request, update maps monitoring it, and return req-id on completion."
  []
  (let [req-id (rand-int 1000)]
    (swap! data-container assoc req-id [])
    (swap! data-deliverer assoc req-id (promise))
    (request-historical-data! req-id); sends the request to distant server
    (deref (get @data-deliverer req-id)); my assumption is this blocks
    req-id))

(defn test-race-1
  "This works and will log all the received quotes"
  []
  (let [req-id (historical-request!)]
    (doseq [hq (get @data-container req-id)]
      (println hq))))

(defn test-race-2
  "This does not work, it will print nothing, even though the request was processed and the data is present, but I presume came too late"
  []
  (doseq [hq (get @data-container (historical-request!))]
    (println hq)))

```

---

<div class="post-metadata">

### Author: ![p-himik](https://clojureverse.org/user_avatar/clojureverse.org/p-himik/32/4137_2.png) [@p-himik](https://clojureverse.org/u/p-himik)
#### Post date: [November 24, 2024, 12:32pm UTC](https://clojureverse.org/t/help-needed-with-a-potential-race-condition/11042/2 "2024-11-24T12:32:02Z")

</div>

Nothing blocks in your code, it’s just that the last `get` returns `nil`. And there are no race conditions either - there’s no asynchronous code of any kind.

The reason for that is that in `test-race-1`, the call to `get` derefs `data-container` after `(historical-request!)`, and in `test-race-2` it happens before `(historical-request!)`, so that `get` receives an old value that doesn’t have that request yet.

One other thing worth noting just in case is that you shouldn’t use code like this in a multithreaded environment. Operations on separate atoms are not synchronized in any way, and that could easily lead to proper race conditions.

---

<div class="post-metadata">

### Author: ![alex314159](https://clojureverse.org/user_avatar/clojureverse.org/alex314159/32/2693_2.png) [@alex314159](https://clojureverse.org/u/alex314159)
#### Post date: [November 24, 2024, 3:20pm UTC](https://clojureverse.org/t/help-needed-with-a-potential-race-condition/11042/3 "2024-11-24T15:20:11Z")

</div>

Eugene, thank you very much, this makes complete sense, in my head things were evaluated right to left and I imagined the rest of the `(get...)` statement would not execute before `historical-request` returned, but I can see this was a big assumption, and the Clojure doc does say things are evaluated left to right anyway!

---

<div class="post-metadata">

### Author: ![ryantate](https://clojureverse.org/user_avatar/clojureverse.org/ryantate/32/4162_2.png) [@ryantate](https://clojureverse.org/u/ryantate)
#### Post date: [November 25, 2024, 3:51pm UTC](https://clojureverse.org/t/help-needed-with-a-potential-race-condition/11042/4 "2024-11-25T15:51:41Z")

</div>

> One other thing worth noting just in case is that you shouldn’t use code like this in a multithreaded environment. Operations on separate atoms are not synchronized in any way, and that could easily lead to proper race conditions

Isn’t this exactly what `ref` and `dosync` are for? There’s a whole STM engine in Clojure for just this scenario, right? 🙂

[https://clojure.org/reference/refs](https://clojure.org/reference/refs)

[https://clojuredocs.org/clojure.core/dosync](https://clojuredocs.org/clojure.core/dosync)

[https://clojuredocs.org/clojure.core/ref](https://clojuredocs.org/clojure.core/ref)

---

<div class="post-metadata">

### Author: ![p-himik](https://clojureverse.org/user_avatar/clojureverse.org/p-himik/32/4137_2.png) [@p-himik](https://clojureverse.org/u/p-himik)
#### Post date: [November 25, 2024, 4:04pm UTC](https://clojureverse.org/t/help-needed-with-a-potential-race-condition/11042/5 "2024-11-25T16:04:50Z")

</div>

Yes. Sometimes it’s also possible to rewrite the code in such a way so that there’s no need for synchronization.

---

<div class="post-metadata">

### Author: ![alex314159](https://clojureverse.org/user_avatar/clojureverse.org/alex314159/32/2693_2.png) [@alex314159](https://clojureverse.org/u/alex314159)
#### Post date: [November 25, 2024, 4:07pm UTC](https://clojureverse.org/t/help-needed-with-a-potential-race-condition/11042/6 "2024-11-25T16:07:13Z")

</div>

thanks both, I don’t really need synchronization between atoms. I have one atom that accumulates data, and one that just accumulates “data is ready” messages which tell the rest of my app that the first atom can be consumed. Welcome ideas as to how to do this better, but the less complexity the better (haven’t found need for e.g. async for instance)

---

<div class="post-metadata">

### Author: ![kopos](https://clojureverse.org/user_avatar/clojureverse.org/kopos/32/3465_2.png) [@kopos](https://clojureverse.org/u/kopos)
#### Post date: [November 28, 2024, 1:35pm UTC](https://clojureverse.org/t/help-needed-with-a-potential-race-condition/11042/7 "2024-11-28T13:35:06Z")

</div>

Wouldn’t a chan be a better approach for this?

```clj
(ns historical-data
  (:require [clojure.core.async :refer [chan >! <!! go close!]]))

(defn request-historical-data!
  [req-id result-chan]
  (go
    (>! result-chan [1 2 3 4])
    (close! result-chan)))

(defn historical-request!
  []
  (let [req-id (rand-int 1000)
        result-chan (chan)]
    (request-historical-data! req-id result-chan)
    result-chan))

(defn test-race-1
  []
  (let [data (<!! (historical-request!))]
    (doseq [hq data]
      (println hq))))

(defn test-race-2
  []
  (doseq [hq (<!! (historical-request!))]
    (println hq)))

(defn -main [& args]
  (test-race-1)
  (test-race-2))

```

---

<div class="post-metadata">

### Author: ![system](https://clojureverse.org/uploads/default/original/2X/5/51079bf9e4b7d9466242c06cf1e43b9f8bd6da14.png) [@system](https://clojureverse.org/u/system)
#### Post date: [May 30, 2025, 1:35am UTC](https://clojureverse.org/t/help-needed-with-a-potential-race-condition/11042/8 "2025-05-30T01:35:26Z")

</div>

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.
