Skip to content

AsapScheduler can interrupt random intervals #7593

@garrisig

Description

@garrisig

Describe the bug

An interval scheduled somewhere else (including rxjs timer) can be unduly canceled by AsapScheduler implementation:

  1. Create a timer with timer(0, intervalDuration, asapScheduler), with intervalDuration > 0
  2. The timer method calls scheduler.schedule(callback, 0) (https://github.com/ReactiveX/rxjs/blob/7.8.2/src/internal/observable/timer.ts#L170C12-L170C30)
  3. The asapScheduler generates an ID from Immediate, we can call it immediateId (https://github.com/ReactiveX/rxjs/blob/7.8.2/src/internal/util/Immediate.ts#L24)
  4. The callback reschedules itself calling schedule(undefined, intervalDuration)
  5. In https://github.com/ReactiveX/rxjs/blob/7.8.2/src/internal/scheduler/AsyncAction.ts#L52, this.id != null, so this.recycleAsyncId(scheduler, id, delay) is called with the id = immediateId and non-zero delay.
  6. asapAction falls back to ayncAction implementation of recycleAsyncId because delay is non-zero (https://github.com/ReactiveX/rxjs/blob/7.8.2/src/internal/scheduler/AsapAction.ts#L30)
  7. asynAction.recycleAsyncId unduly clears an interval with id = immediateId https://github.com/ReactiveX/rxjs/blob/7.8.2/src/internal/scheduler/AsyncAction.ts#L79

Expected behavior

The AsapScheduler should be protected in order not to affect unrelated code.

The AsyncScheduler could be protected as well by using the type-system to ensure that only ids generated by setInterval are passed to clearInterval

Reproduction code

import { asapScheduler, timer } from 'rxjs';

let n = 0;

const a = setInterval(() => console.log(n++), 200);

console.log(`interval id: ${a}`);
setTimeout(() => {
  timer(0, 10000, asapScheduler).subscribe(() => console.log("I did not eat the other interval"));
}, 1);

setTimeout(() => {
  timer(0, 10000, asapScheduler).subscribe(() => console.log("I did not eat the other interval"));
}, 2);

setTimeout(() => {
  timer(0, 10000, asapScheduler).subscribe(() => console.log("I ate the other interval"));
}, 3);

Reproduction URL

No response

Version

<= 7.8.2

Environment

Any environment. Happens at least in

  • Firefox 147
  • Chromium 145
  • Node version v22.20.0

The reproduction code was tested in Node 22.20.0

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions