-
Notifications
You must be signed in to change notification settings - Fork 107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document whether fetch/4
is an atomic operation
#393
Comments
@1player it is not atomic, otherwise it would be documented as such. I'm not sure why you would say it's not useful for that reason; why would you want to block your entire cache on an operation that could take (in some cases) multiple seconds? You are correct that a naive implementation of This behaviour is documented here (which is also available on the published documentation). Does this answer your question? What would you change in the documentation? |
Thank you for clarifying!
I assumed the lack of any mention regarding atomicity to just be an oversight, rather than implicitly saying that it is not atomic. I think it would be more useful to mention this fact explicitly in the The cache warmer example you have linked are quite useful and clearly answer my question, yet I didn't come across it because I have no need for cache warming so I never thought to look there for answers :) |
Apologies, now I am confused. You say:
So if no overlapping calls are allowed, it's basically "atomic", i.e. it operates as if that key is locked while a fetch operation is executing, which is exactly what I need. That's what I understand from your comment. Since I'm apparently too slow, and you haven't confirmed explicitly: can I use |
No problem! Let me try to be clearer, it is a bit awkward to explain in words. It might be clearer with examples: If you do something like this: Cachex.fetch(:cache, :my_key, fn ->
:timer.sleep(5000)
:ok
end) Other writes to keys can still be running in the background, and that includes the key Cachex.put(:cache, :my_key, :my_value) In this case what would happen is after the 5s, your
Yep! That's where # start a new cache
Cachex.start(:cache)
# via get_and_update/4
for _ <- 1..10 do
spawn(fn ->
Cachex.get_and_update(:cache, "key1", fn value ->
IO.puts("Running get_and_update/4 handler")
case value do
nil -> :timer.sleep(1000)
value -> value
end
end)
end)
end
# via fetch/4
for _ <- 1..10 do
spawn(fn ->
Cachex.fetch(:cache, "key2", fn key ->
IO.puts("Running fetch/4 handler")
value = :timer.sleep(1000)
value
end)
end)
end If you run this, you'll see that the function you provide to Does this make more sense? I'm happy to clarify anything if it's still confusing. |
Use case: I want to fetch a key from Cachex, or run an expensive operation to generate it. In a multi-node cluster, I'd like to do the operation once, which means that the key should be locked until the fallback function returns.
#190 clarified that
get_and_update/4
is atomic and uses transactions, yet it is not clear to me whetherfetch/4
is. If it is not atomic, I wonder it's usefulness given thatget_and_update/4
is, and thus is more reliable in many scenarios.So this issue is to ask whether my assumptions are correct, and that perhaps the documentation should be a bit more clear about it.
The text was updated successfully, but these errors were encountered: