commit 4504af9d71441f0ddfcb6859489c1540a9d21971
parent f4b336d78f72501d8bb76010de02640b23783e03
Author: triesap <tyson@radroots.org>
Date: Sun, 24 May 2026 21:51:37 +0000
app: enqueue order sync after recovery retry
Diffstat:
1 file changed, 132 insertions(+), 11 deletions(-)
diff --git a/crates/launchers/desktop/src/runtime.rs b/crates/launchers/desktop/src/runtime.rs
@@ -1484,15 +1484,7 @@ impl DesktopAppRuntimeState {
)?;
}
let pending_changed = if matches!(buyer_context, BuyerContext::Account(_)) {
- self.enqueue_selected_account_sync_operations(vec![pending_sync_upsert(
- SyncAggregateRef::Order(order_id),
- order_sync_payload(
- order_id,
- order_detail.farm_id,
- "place_personal_order",
- Some("needs_action"),
- ),
- )])?
+ self.enqueue_selected_account_order_sync_operation(order_id, order_detail.farm_id)?
} else {
false
};
@@ -1540,6 +1532,12 @@ impl DesktopAppRuntimeState {
)?
};
if order_changed {
+ if matches!(buyer_context, BuyerContext::Account(_)) {
+ let _ = self.enqueue_selected_account_order_sync_operation(
+ order_export.order_id,
+ order_export.farm_id,
+ )?;
+ }
refreshed_order_id.get_or_insert(record.order_id);
changed = true;
}
@@ -3224,6 +3222,53 @@ impl DesktopAppRuntimeState {
self.refresh_selected_account_sync()
}
+ fn enqueue_selected_account_order_sync_operation(
+ &mut self,
+ order_id: OrderId,
+ farm_id: FarmId,
+ ) -> Result<bool, AppSqliteError> {
+ self.enqueue_selected_account_sync_operation_once(pending_sync_upsert(
+ SyncAggregateRef::Order(order_id),
+ order_sync_payload(
+ order_id,
+ farm_id,
+ "place_personal_order",
+ Some("needs_action"),
+ ),
+ ))
+ }
+
+ fn enqueue_selected_account_sync_operation_once(
+ &mut self,
+ operation: PendingSyncOperation,
+ ) -> Result<bool, AppSqliteError> {
+ let Some(account_id) = self
+ .state_store
+ .identity_projection()
+ .selected_account
+ .as_ref()
+ .map(|account| account.account.account_id.clone())
+ else {
+ return Ok(false);
+ };
+ let already_enqueued = {
+ let Some(sqlite_store) = self.sqlite_store.as_ref() else {
+ return Ok(false);
+ };
+ let existing = sqlite_store.load_pending_sync_operations(account_id.as_str())?;
+ existing.iter().any(|pending| {
+ pending.operation.aggregate == operation.aggregate
+ && pending.operation.operation == operation.operation
+ && pending.operation.payload_json == operation.payload_json
+ })
+ };
+ if already_enqueued {
+ return self.refresh_selected_account_sync();
+ }
+
+ self.enqueue_selected_account_sync_operations(vec![operation])
+ }
+
fn selected_account_id(&self) -> Result<String, DesktopAppRuntimeFarmSetupError> {
self.selected_account_for_farm_setup()
.map(|account| account.account.account_id.clone())
@@ -8658,6 +8703,23 @@ mod tests {
.expect("buyer order should place")
);
let order_id = runtime.summary().personal_projection.orders.list.rows[0].order_id;
+ let order_farm_id = runtime
+ .summary()
+ .personal_projection
+ .orders
+ .detail
+ .as_ref()
+ .expect("buyer order detail")
+ .farm_id;
+ assert_eq!(
+ pending_order_sync_payloads(&runtime, buyer_account_id.as_str(), order_id),
+ vec![super::order_sync_payload(
+ order_id,
+ order_farm_id,
+ "place_personal_order",
+ Some("needs_action")
+ )]
+ );
{
let state = runtime.lock_state_mut();
@@ -8790,6 +8852,15 @@ mod tests {
.generate_local_account(Some("Buyer".to_owned()))
.expect("account should generate")
);
+ let buyer_account_id = runtime
+ .summary()
+ .settings_account_projection
+ .selected_account
+ .as_ref()
+ .expect("selected account")
+ .account
+ .account_id
+ .clone();
assert!(
runtime
.select_active_surface(ActiveSurface::Personal)
@@ -8840,8 +8911,15 @@ mod tests {
assert!(summary.personal_projection.cart.cart.lines.is_empty());
assert!(!summary.personal_projection.cart.checkout.can_place_order);
assert_eq!(summary.personal_projection.orders.list.rows.len(), 1);
- let order_id = {
+ let (order_id, order_farm_id) = {
let visible_order_id = summary.personal_projection.orders.list.rows[0].order_id;
+ let order_farm_id = summary
+ .personal_projection
+ .orders
+ .detail
+ .as_ref()
+ .expect("buyer order detail should remain visible after coordination failure")
+ .farm_id;
assert_eq!(
summary
.personal_projection
@@ -8870,8 +8948,17 @@ mod tests {
assert!(coordination.record_id.is_some());
assert!(coordination.payload_json.is_some());
assert!(coordination.last_error_message.is_some());
- order_id
+ (order_id, order_farm_id)
};
+ assert!(
+ pending_order_sync_payloads(&runtime, buyer_account_id.as_str(), order_id).is_empty()
+ );
+ let expected_order_sync_payload = super::order_sync_payload(
+ order_id,
+ order_farm_id,
+ "place_personal_order",
+ Some("needs_action"),
+ );
{
let state = runtime.lock_state_mut();
let sqlite_store = state.sqlite_store.as_ref().expect("sqlite store");
@@ -8891,6 +8978,10 @@ mod tests {
);
let summary_after_retry = runtime.summary();
assert_eq!(
+ pending_order_sync_payloads(&runtime, buyer_account_id.as_str(), order_id),
+ vec![expected_order_sync_payload.clone()]
+ );
+ assert_eq!(
summary_after_retry
.personal_projection
.orders
@@ -8951,6 +9042,10 @@ mod tests {
.retry_pending_personal_order_coordination()
.expect("same-session synced buyer order recovery retry should be idempotent")
);
+ assert_eq!(
+ pending_order_sync_payloads(&runtime, buyer_account_id.as_str(), order_id),
+ vec![expected_order_sync_payload]
+ );
drop(runtime);
let restarted_runtime = restart_runtime(paths.clone());
@@ -8987,6 +9082,11 @@ mod tests {
.retry_pending_personal_order_coordination()
.expect("synced buyer order recovery retry should be idempotent")
);
+ assert_eq!(
+ pending_order_sync_payloads(&restarted_runtime, buyer_account_id.as_str(), order_id)
+ .len(),
+ 1
+ );
cleanup_bootstrapped_runtime_paths(&paths);
}
@@ -12465,6 +12565,27 @@ mod tests {
.expect("shared local records should list")
}
+ fn pending_order_sync_payloads(
+ runtime: &DesktopAppRuntime,
+ account_id: &str,
+ order_id: OrderId,
+ ) -> Vec<String> {
+ runtime
+ .lock_state()
+ .sqlite_store
+ .as_ref()
+ .expect("sqlite store")
+ .load_pending_sync_operations(account_id)
+ .expect("pending sync operations should load")
+ .into_iter()
+ .filter(|pending| {
+ pending.operation.operation == SyncOperationKind::Upsert
+ && matches!(pending.operation.aggregate, SyncAggregateRef::Order(id) if id == order_id)
+ })
+ .map(|pending| pending.operation.payload_json)
+ .collect()
+ }
+
fn block_shared_local_events_database(paths: &AppDesktopRuntimePaths) {
let database_path = paths
.shared_local_events_database_path()