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

Proposal: Support time-travel debugging (still editing) #4529

justinbmeyer opened this Issue Oct 11, 2018 · 2 comments


None yet
2 participants
Copy link

justinbmeyer commented Oct 11, 2018

tldr; We should support time travel debugging. People should be able to go back to a previous state.


There are a few things we need to be able to do:

  1. Record all state changes
  2. Set state changes without causing side-effects (except for those we want ).

Naive approach

Record all state changes

Similar to can.onInstancePatches and log(), we probably need a global state change handler. Dispatching to this should be removed in production. We will record all state changes.

As we have two different types of observables (objects and single-value) we need to store different things:

  • objects -> the object that changed and patches
  • single value observables -> the observable that changed and the new value

Set state changes without causing side effects (except for updating the DOM or URL).

This is the hardest part. Ideally, we could simply update every observable with its value
and we'd have what we need.

This will not be easy because we need some things to run their side effects:

  • can-view-live rendering sub-sections
  • creating components / removing components

We could differentiate these listeners from normal "side-effect" listeners. Maybe the MUTATE queue is this differentiator.

Queues approach

Here we will record only the first state changes that causes the queues to start. These are "root causes". Queues already knows when this happens because there is no parentTask.

We store these and can play setting the opposite value in reverse.


What if a component is created and does something like:

ViewModel: {
       this.passedValue++ //<-- no "parentTask", considered a "root" cause

Upon playing "forward", this.passedValue would run, but it would be considered a "root" cause (unless we use zones). We would probably want to ignore these.

Essentially, while playing forward, any "root causes" that happened as as result of us updating the state, we would ignore when performing the next step.

Other considerations

I've tried to pencil out what a "slow mode" queues system would look like. "Slow Mode" would run tasks exactly the same as the current synchronous queues system, except it would allow time between each task.

This was not an easy task. There were challenges mimicking the exact nature of the queues. I think this might be impossible. Impossible largely because any .flush() within an already running queue was expected to restart a dispatch and finish all currently queued tasks before the statement after .flush() runs.

I don't think a "slow-mode" queue is necessary for time-travel debugging because we won't need to be that fined grained. However, it would be nice for some difficult to figure out bugs.


This comment has been minimized.

Copy link

justinbmeyer commented Oct 12, 2018

I don't know how much people want to debug microscopically vs macroscopic

MICRO: say someone clicks a button, and they want to break down everything that happens as a result of that bug click ... as values get passed from one component to another. This is what can-queues.logStack() does. But I think time-travel is VERY difficult on this level without something like a "slow mode" queue.

MACRO: You click one button, then another button, then submit a form, then do something else. We can do time travel for these things.


This comment has been minimized.

Copy link

frank-dspeed commented Dec 18, 2018

@justinbmeyer maybe something as simple as logging can-queue? and preserve state in a browser storage solution ? or as simple as offer a external endpoint to post the log to via api? Observation of can-queue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment