We're seeing some very strange behavior with speculative databases in Datomic Cloud. Sometimes when retracting an entity speculatively, a query immediately after the speculative transaction shows the entity has not been retracted! Sometimes, it shows the entity has been transacted. Here is a transcript of a REPL session executing the same expression twice in a row:
user.unwind>
(let [wdb (d/with-db (:datomic/connection @user/sysref))
pol [:st.purchase-order.line/purchase-order-id+number [15900 720]]
txd [[:db/retractEntity pol]]
result (d/pull wdb {:selector ['*] :eid pol})
{:keys [db-after tx-data]} (d/with wdb {:tx-data txd})]
[wdb txd (d/pull db-after {:selector ['*] :eid pol})])
[{:database-id "e684b9c0-af66-450f-b29b-da7e6f080575", :db-name "stt", :t 18620961, :next-t 18620962, :next-token "qlG2LYVPqXQTliRMZXwRVFLjxjRXfQroaPNrIVWgKbBgChvbZYBJlXwj33IPKaYsK4WgVVS+g7nIPjhsP1H4hg==", :type :datomic.client/db}
[[:db/retractEntity [:st.purchase-order.line/purchase-order-id+number [15900 720]]]]
#:db{:id nil}]
user.unwind>
(let [wdb (d/with-db (:datomic/connection @user/sysref))
pol [:st.purchase-order.line/purchase-order-id+number [15900 720]]
txd [[:db/retractEntity pol]]
result (d/pull wdb {:selector ['*] :eid pol})
{:keys [db-after tx-data]} (d/with wdb {:tx-data txd})]
[wdb txd (d/pull db-after {:selector ['*] :eid pol})])
[{:database-id "e684b9c0-af66-450f-b29b-da7e6f080575", :db-name "stt", :t 18620963, :next-t 18620964, :as-of 18620961, :next-token "sb7b3by2hDYTuABH0hcCUa73mnmLxWXj4lgKCyw4LxkVQ7vOWOzMIZcDYKb8VpTkBLLVfE80GpThF6NV57VdKuFQbt3yFzzMFXAW3qlfyIY=", :type :datomic.client/db}
[[:db/retractEntity [:st.purchase-order.line/purchase-order-id+number [15900 720]]]]
{:db/id 7938473973803978,
:st.purchase-order.line/item #:db{:id 5818615551342135},
:st.purchase-order.line/estimated-receipt-on "#time/date \"2023-01-10\"",
:st.purchase-order.line/number-v2 720,
:st.purchase-order.line/purchase-order-id+number [15900 720],
:st.purchase-order.line/blanket-period "#st/year-month-range \"2022-12/P1M\""}]
user.unwind>
In the first execution of the speculative transaction, the entity has been retracted and d/pull returns the usual marker for an unresolved lookup ref. But in the second execution of the speculative transaction (executed no more than two seconds after the first) the entity was not retracted! The speculative transaction did not throw nor did the d/pull with the :db-after value of the transaction.These tests were performed from a local REPL against the https://docs.datomic.com/changes/cloud.html#1217-9399.
(the binding of result to (d/pull wdb {:selector ['*] :eid pol}) is superfluous... it was part of a debugging effort that did not bear fruit.)
Curious, what happens if pol isn't a lookup ref(or an attempt at, sorry thinking out loud) but an entity id i.e db/id value (7938473973803978)?
First attempt using :db/id yields the "happy path" where the retracted entity is indeed removed:
(let [wdb (d/with-db (:datomic/connection @user/sysref))
pol 7938473973803978
txd [[:db/retractEntity pol]]
result (d/pull wdb {:selector ['*] :eid pol})
{:keys [db-after tx-data]} (d/with wdb {:tx-data txd})]
[wdb txd (d/pull db-after {:selector ['*] :eid pol})])
[{:database-id "e684b9c0-af66-450f-b29b-da7e6f080575", :db-name "stt", :t 18627683, :next-t 18627684, :next-token "aXsglUw0q7c4q8SqaN26ZP8ONBpxgSlW/B2wUPmWiucwl+bWONBSaayA3/SYcsOSEx3/V2BPa70VIAGro5219g==", :type :datomic.client/db}
[[:db/retractEntity 7938473973803978]]
#:db{:id 7938473973803978}]
...but keep in mind that the results are not deterministic and the unhappy path seems to be more likely if the client has "quiesced" for a bit. I'll try again in a moment and see if I can get the :db/id version to fail.(also, obviously for those familiar with the quirks of pulling a non-existent entity, the return value for d/pull is different but consistent with "no entity")
Try and if it fails, report, so I could reproduce and experiment the same scenario on my machine.
Yep, after a "quiesce" period, it failed.
The 1st run: wdb is a db value at :t 18620961 While the 2nd run: wdb is not the same db value because I see it now includes :as-of 18620961 while :t has advanced to 18620963
However, I dont see where you are calling as-of . Where are you getting your db value from? does this @user/sysref possibly wrap the db in an as-of? Once you are using a lookup ref inside a as-of the results may appear nondeterministic.
Resolving the entity id in wdb first and then retracting by eid will result in deterministic behavior as a workaround.
I think this comes down to expecting as-of as a branch: https://docs.datomic.com/reference/filters.html#as-of-not-branch
The connection from user/sysref is a "plain" connection -there is no call to as-of.
huh. Thats interesting then. Let me try to figure out why your return shows an as-of
That struck us as kinda weird too.
FWIW, the subject of the :db/retractEntity is also the subject of an isComponent relationship.
Note also that there is no :as-of attr on the db in the second case where things worked as expected. I just ran the test a couple of times in the REPL (with the same connection as yesterday) and when it works, there is no :as-of and when it fails, there is an :as-of. IIRC, @lwhorton observed the same correlation yesterday.
Another observation: I cannot provoke the failure if I use a fresh connection. If I "recycle" a connection that has been used for other activities then the problem sometimes appears.