Fork me on GitHub

Hi, I’m struggling with a bug. I’ve tried to make a minimal example of the code. When running this code I can see from the tap> that sometimes cache resets to an empty map {}. Anyone have an idea what I’m doing wrong?

(let [in (chan)
      tags [:some :list :of :tags]
      f some-function]

  (go-loop [cache {}]
    (let [{:keys [tag payload]} (<! in)
          new-cache (assoc cache tag payload)
          result (apply f (for [tag tags] (get new-cache tag)))]

      (tap> {:cache cache
             :new-cache new-cache
             :result result})

      (recur new-cache)))


Have you restarted your repl recently? My guess is you have some other code running, maybe an earlier version of that loop


@hiredman have restarted many times since finding this bug. Pretty sure that’s not the problem


It kind of has to be. What did does that tap result look like that is making you thing cache is becoming {} ?


Are you seeing {} in that tap output and concluding that cache has become {} when in fact that would be {:cache {} :new-cache ... :new-result ...} ?


@hiredman yes but also :new-cache seems to reset


Or am I misinterpreting something?


Are you sure you are looking at the correct file? I've seen people edit one copy and run another. Are you sure you are saving the file after edits?


What effect would saving the file have?


You can put an (assert nil) at the top of the loop to determine if that code is actually being run, and an (assert (not-empty? new-cache)) later on in the loop to determine if that loop is the source of those tap messages


I dunno how you are running all this


If you are telling your editor to eval the file, it may load the file from disk instead of the contents of the unsaved buffer


I’m using chlorine and it’s command to evaluate a specific form. But I will try your suggestions to make sure I’m looking at the right code.


The assert nil will cause an error if the code you are looking at is actually run, then you can remove it, and then the asset not empty will fire if new cache ever does become empty in that code


Are you sure you have actually restarted your repl?


Does chlorine just keep a repl around and opening and closing the repl window or whatever just reconnects you to it?


It connects to a running socket REPL.


The repl keeps going even if you close Atom. It’s started in a terminal window


Could be that my minimal example doesn’t show enough to pinpoint the problem


I didn't catch that that isn't what is actually breaking


If you actual code is building the cache with something more complicated then assoc the problem is likely there


Is it an actual cache with ttls? Then becoming empty has to be expected behavior


Nope that part is the same as the actual code. The assoc I mean


It’s just a regular map that I associate into


The only thing thats missing from my example is that i put (`>!`) result on some channels


In the example code, cache only grows in size, which is kind of atypical for a cache, is there any code at all that removes or expires entries


I guess is doesn't grow beyond a constant size, the number of tags, in the example


The number of tags is indeed constant. It just takes the most recent value with the tag, assocs it into the cache and reruns the function f using all the values in the cache.


And the result is put on some channels


I can't debug it without more information, either more detail of the real code, or the results of the asserts I suggested. I strongly recommend finding your invariants like new cache is always greater than or equal to cache in size, and asserting it in as many places as possible in code you are debugging


Because what you are looking for is the first place that invariant is violated


Will try some more things tomorrow and check back here if needed. Thanks for the tips!