Skip to content
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

Fix infinite feedback loop between Action states #221

Merged
merged 2 commits into from
Jan 13, 2017

Conversation

sharplet
Copy link
Contributor

Fixes #220.

There is a potentially circular relationship between Action.isEnabled and Action.isExecuting. It's valid for users to observe properites on Action and feed the output back into the action state, and in turn influence Action.isEnabled.

This resolves an issue where:

  1. The user supplies a condition as the action enabled state
  2. Any property derived from the internal Action.state is observed
  3. Synchronously, the observer updates the user-supplied state property
  4. Which updates the internal state property
  5. Which causes an externally-observable event to fire, returning to (3), indefinitely.

The reason for this manifesting as an infinite loop, rather than an infinite recursion, is the internal use of a replayLazily in Property: each time a side effect on the user-supplied property occurs, that queues up another event inside the replayed signal producer, and the observer is never attached because there is always a buffered event to consume.

The issue was that multiple events were firing synchronously when observing Action.isExecuting, even though the executing state had never changed. The fix is to skip repeats on Action.isEnabled and Action.isExecuting, so that observers are only ever notified if the value actually changes, instead of whenever something triggeres a side-effect on the internal state.

Fixes #220.

There is a potentially circular relationship between `Action.isEnabled`
and `Action.isExecuting`. It's valid for users to observe properites on
`Action` and feed the output back into the action state, and in turn
influence `Action.isEnabled`.

This resolves an issue where:

1. The user supplies a condition as the action enabled state
2. Any property derived from the internal `Action.state` is observed
3. Synchronously, the observer updates the user-supplied state property
4. Which updates the internal `state` property
5. Which causes an externally-observable event to fire, returning to
   (3), indefinitely.

The reason for this manifesting as an infinite loop, rather than an
infinite recursion, is the internal use of a `replayLazily` in
`Property`: each time a side effect on the user-supplied property
occurs, that queues up another event inside the replayed signal
producer, and the observer is never attached because there is always a
buffered event to consume.

The issue was that multiple events were firing synchronously when
observing `Action.isExecuting`, even though the executing state had
never changed. The fix is to skip repeats on `Action.isEnabled` and
`Action.isExecuting`, so that observers are only ever notified if the
value actually changes, instead of whenever something triggeres a
side-effect on the internal state.
@mdiep mdiep merged commit 3925cad into master Jan 13, 2017
@mdiep mdiep deleted the as-fix-action-replay-loop branch January 13, 2017 13:34
@mdiep
Copy link
Contributor

mdiep commented Jan 13, 2017

Thanks for fixing this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Action behavior: Changing enabledIf condition in a observer of isExecuting.producer leads to infinite loop
2 participants