Make full-payload and append refreshes transactional

Open
#431 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
45/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet

Research direction

Start with updatePayload() in js/src/56_animation.ts, the append path in js/src/54_kernel.ts, and payloadVersion handling in python/reflex_xy/assets/XYChart.jsx. Trace provisional GPU and transition ownership before adding commit or rollback behavior. Done means fault-injection and browser checks preserve the last good chart, balance resource cleanup, and allow a later valid refresh.

Written by the indexing model from the issue text.

Description

Summary

Client payload refreshes mutate authoritative chart state and GPU resources before the replacement has been built successfully. If trace construction fails partway through a full update or append, the chart can retain a new spec with old GPU traces, leak provisional resources, or hold a destroyed old trace. The Reflex wrapper also advances its payload generation before the view accepts the update.

Audited at commit 99eda6d.

Current behavior

updatePayload() commits spec, interaction/style state, axes, _payload, and the new home view before mapping all new traces through _buildTrace() (56_animation.ts). If a later trace throws, earlier provisional GPU allocations are not owned by a cleanup set, gpuTraces still refers to the previous array, and the already-committed metadata describes the new payload.

The non-animated append path commits the new spec/payload, then destroys each old trace before constructing its replacement (54_kernel.ts). A replacement build failure leaves the array pointing at an object whose resources were already destroyed.

The Reflex wrapper sets payloadVersion before calling updatePayload() or constructing a replacement ChartView, with no transaction around the whole operation (XYChart.jsx).

A fault-injection probe that threw on the second trace build left new metadata committed, the old GPU list attached, and one provisional allocation uncollected.

Proposed direction

Build the complete replacement into local provisional state, including every GPU resource and transition object. Commit the spec, axes, payload, view state, and GPU list only after all construction and transition preparation succeeds. On failure, destroy all provisional resources and keep the last known-good scene intact.

For append replacement, build first and only destroy/swap the old trace after success. The Reflex wrapper should advance the accepted generation only after updatePayload() or new ChartView construction succeeds.

Acceptance criteria
  • updatePayload() is atomic from the caller's perspective: success commits the complete replacement; failure leaves the prior spec, payload, axes, view, and GPU traces usable.
  • Every provisional resource is destroyed when any trace build or transition-preparation step fails.
  • Append replacement builds the new trace before destroying the old one.
  • A failed append leaves the previous trace renderable and the prior canonical payload/restoration state intact.
  • Reflex advances payloadVersion, clears awaitingPayload, and replays queued state only after the view accepts the payload.
  • Fault-injection tests throw on the first, middle, and last trace builds and assert state identity plus balanced GPU allocation/deletion counts.
  • Browser coverage confirms that a recoverable refresh failure preserves the last good chart and a later valid refresh still succeeds.
Related, not duplicate

#163 tracks the bandwidth cost of re-shipping full payloads, and #237 tracks cancellation of stale fetches. Neither covers commit/rollback semantics or GPU lifetime on a failed replacement.

Dominant language
Python
Stars
1.8k
Forks
76
Avg merge
1h 7m
Merged PRs (30d)
8

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from reflex-dev/xy

All issues in reflex-dev/xy

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.