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

Executing a cancelled action #5671

Closed
haf opened this issue Aug 24, 2020 · 13 comments
Closed

Executing a cancelled action #5671

haf opened this issue Aug 24, 2020 · 13 comments

Comments

@haf
Copy link

haf commented Aug 24, 2020

Bug Report

Current Behavior
This code is throwing "Executing a cancelled action " after a while:

import { Observable } from "rxjs"

export default function visibilityState(): Observable<VisibilityState> {
  return new Observable(o => {
    o.next(window.document.visibilityState) // throws here!

    const handle = () => o.next(window.document.visibilityState)

    window.addEventListener('visibilitychange', handle)
    return () => window.removeEventListener('visibilitychange', handle)
  })
}

At this callsite:

image

which is in turn called from:

image

Stacktrace; and "Angular" is nowhere near my code, I assure you.

Uncaught Error: executing a cancelled action
    RxJS 2
        execute
        flush
    Angular 8
        invokeTask
        runTask
        invokeTask
        invoke
        timer
        setInterval handler*scheduleTask
        scheduleTask
        scheduleTask
AsyncAction.js:49
    RxJS 2
        execute
        flush
    <anonymous> self-hosted:982
    Angular 12
        invokeTask
        runTask
        invokeTask
        invoke
        timer
        (Async: setInterval handler)
    scheduleTask
        scheduleTask
        scheduleTask
        scheduleMacroTask
        scheduleMacroTaskWithCurrentZone
        setNative
        name
    RxJS 44
        requestAsyncId
        schedule
        schedule
        schedule
        interval
        _trySubscribe
        subscribe
        innerSubscribe
        _innerSub
        _tryNext
        _next
        next
        subscribeToArray
        _trySubscribe
        subscribe
        call
        subscribe
        subscribeToResult
        _complete
        complete
        subscribeToArray
        _trySubscribe
        subscribe
        call
        subscribe
        call
        subscribe
        innerSubscribe
        openBuffer
        notifyNext
        _next
        next
        _next
        next
        notifyNext
        _next
        next
        notifyNext
        _next
        next
        _next
        next
        _next
        next
    visibilityState visibilityState.js:6
    RxJS 43
    visibilityState visibilityState.js:6
    RxJS 25

Reproduction:

This repeats when I switch tabs, after a while. I'm not sure why: the calling code looks like this:

const triggerOnChangeTab = () => {
  if (typeof window === 'undefined') return from([])
  return visibilityState().pipe(
    filter(x => x === 'hidden'),
    tap(() => console.debug('visibilityState => "hidden"'))
  )
}

export default function periodicRequest<TRes>(
  connectivityStream: () => Observable<boolean>,
  makeRequests: Observable<TRes>,
  period: number = 500,
  extraTriggers: () => Observable<string> = triggerOnChangeTab
) {
  const trigger = () =>
    combineLatest([
      connectivityStream(),
      // this second parameter acts as the trigger, either every broadcast interval, or when the page is hidden
      merge(interval(period), extraTriggers())
    ]).pipe(filter(([online, _]) => online))

  return makeRequests.pipe(bufferWhen(trigger))
}

According to the code, in visibilityState; the crash comes immediately, so perhaps the observable is created and immediately cancelled, causing this issue.

Expected behavior
A clear and concise description of what you expected to happen (or code).

Environment

  • Runtime: [e.g. Node v${x}, Chrome v${x}] Firefox 79
  • RxJS version:
rxjs@^6.3.3:
  version "6.6.2"
  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.2.tgz#8096a7ac03f2cc4fe5860ef6e572810d9e01c0d2"
  integrity sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==
  dependencies:
    tslib "^1.9.0
  • (If bug is related) Loader, build configuration: [e.g webpack, angular-cli version, config]: nextjs:

next@^9.4.2:
  version "9.5.2"
  resolved "https://registry.yarnpkg.com/next/-/next-9.5.2.tgz#ef9b77455b32dca0e917c763529de25c11b5c442"
  integrity sha512-wasNxEE4tXXalPoUc7B5Ph3tpByIo7IqodE9iHhp61B/3/vG2zi2BGnCJjZQwFeuotUEQl93krz/0Tp4vd0DsQ==
  dependencies:
    "@ampproject/toolbox-optimizer" "2.6.0"
    "@babel/code-frame" "7.8.3"
    "@babel/core" "7.7.7"
    "@babel/plugin-proposal-class-properties" "7.8.3"
    "@babel/plugin-proposal-export-namespace-from" "7.10.4"
    "@babel/plugin-proposal-nullish-coalescing-operator" "7.8.3"
    "@babel/plugin-proposal-numeric-separator" "7.8.3"
    "@babel/plugin-proposal-object-rest-spread" "7.9.6"
    "@babel/plugin-proposal-optional-chaining" "7.9.0"
    "@babel/plugin-syntax-bigint" "7.8.3"
    "@babel/plugin-syntax-dynamic-import" "7.8.3"
    "@babel/plugin-transform-modules-commonjs" "7.9.6"
    "@babel/plugin-transform-runtime" "7.9.6"
    "@babel/preset-env" "7.9.6"
    "@babel/preset-modules" "0.1.3"
    "@babel/preset-react" "7.9.4"
    "@babel/preset-typescript" "7.9.0"
    "@babel/runtime" "7.9.6"
    "@babel/types" "7.9.6"
    "@next/react-dev-overlay" "9.5.2"
    "@next/react-refresh-utils" "9.5.2"
    ast-types "0.13.2"
    babel-plugin-syntax-jsx "6.18.0"
    babel-plugin-transform-define "2.0.0"
    babel-plugin-transform-react-remove-prop-types "0.4.24"
    browserslist "4.13.0"
    buffer "5.6.0"
    cacache "13.0.1"
    chokidar "2.1.8"
    crypto-browserify "3.12.0"
    css-loader "3.5.3"
    cssnano-simple "1.0.7"
    find-cache-dir "3.3.1"
    jest-worker "24.9.0"
    loader-utils "2.0.0"
    mini-css-extract-plugin "0.8.0"
    mkdirp "0.5.3"
    native-url "0.3.4"
    neo-async "2.6.1"
    node-html-parser "^1.2.19"
    path-browserify "1.0.1"
    pnp-webpack-plugin "1.6.4"
    postcss "7.0.32"
    process "0.11.10"
    prop-types "15.7.2"
    prop-types-exact "1.2.0"
    react-is "16.13.1"
    react-refresh "0.8.3"
    resolve-url-loader "3.1.1"
    sass-loader "8.0.2"
    schema-utils "2.6.6"
    stream-browserify "3.0.0"
    style-loader "1.2.1"
    styled-jsx "3.3.0"
    use-subscription "1.4.1"
    vm-browserify "1.1.2"
    watchpack "2.0.0-beta.13"
    web-vitals "0.2.1"
    webpack "4.44.1"
    webpack-sources "1.4.3"

Possible Solution
Don't crash the "constructor"; it doesn't matter as a user what scheduler you're using, if the constructor (aka. callback that instantiates the observable) can't run to completion.

Noteworthy:

I also have this package installed and initialised in the browser, which might affect your usage of Zone.js (if you're using it):

"@opentelemetry/web@^0.10.1":
  version "0.10.2"
  resolved "https://registry.yarnpkg.com/@opentelemetry/web/-/web-0.10.2.tgz#c5efc4444d45aef822913044ab003a9db30aea4a"
  integrity sha512-ZJQ8Pbm3pTkoyZSkIOq1cZrmRL+HuTC4KTOnzE5qUg3+5h608zyRT1PMIIhR8+mvFZLHcDyGrs7sSJfpW7a6iw==
  dependencies:
    "@opentelemetry/api" "^0.10.2"
    "@opentelemetry/context-base" "^0.10.2"
    "@opentelemetry/core" "^0.10.2"
    "@opentelemetry/semantic-conventions" "^0.10.2"
    "@opentelemetry/tracing" "^0.10.2"
@haf
Copy link
Author

haf commented Aug 26, 2020

Ping

@cartant
Copy link
Collaborator

cartant commented Sep 5, 2020

... after a while ... repeats when I switch tabs, after a while

Without a minimal reproduction, there's not a great deal that can be done here. AFAICT, the unsubscription mechanism with AsyncAction - which is what's employed within the interval implementation - has no obvious errors. IMO, what you should do is prove - via logging - that the setInterval and clearInterval calls are not being called as would be expected based on the unsubscription mechanism. Add logging (of the call and the ID) here:

return setInterval(scheduler.flush.bind(scheduler, this), delay);

and here:

clearInterval(id);

If the calls are not being made as expected - there should be one setInterval and one clearInterval per subscription to the interval - I can take a closer look, but, ATM, there is too much other code - application and zone, etc. - involved for this to be a worthwhile exercise. If the calls are made as expected, I'd say the problem is elsewhere.

@pshurygin
Copy link

I'm facing the same issue randomly when running karma unit tests and angular. Some runs are fine, some are failing.
I've checked the setInterval/clearInterval calls and it seems they are called correctly even when the error pops up(number of calls to setInterval equals number of calls to clearInterval). The subscriptions are also correctly unsubscribed.

In my case the issue originates from the usage of the throttleTime(), which uses asyncSubscriber under the hood. Also, zone.js is used, which patches the setInterval, which may somehow conflict with rxjs in this instance.

@cartant Any advice on how I can investigate this further? Here are the stacktraces:

Screenshot 2020-10-29 at 21 41 20
Screenshot 2020-10-29 at 21 40 00

@cartant
Copy link
Collaborator

cartant commented Oct 29, 2020

@pshurygin Instead of commenting on a closed issue, it's always preferable to open a new issue, fill out the template and refer the related issue. IDK what version you are using, etc.

Regarding what you can do next:

  • Does it always fail in the same test?
  • Does it fail if only that test runs?
  • Does it fail if that test and a subset of the other tests run?
  • What does the code in the test look like? Can it be simplified? Make it as simple as possible and then post the code. (In the separately-opened issue that includes your version information, etc.)

Fundamentally, the aim is to reduce the scenario that effects the problem to be as simple as possible. Hopefully, simple enough to share so that someone else can reproduce it.

@kwonoj I thought we had a bot that locked inactive, closed issues. Is that no longer a thing?

@kwonoj
Copy link
Member

kwonoj commented Oct 30, 2020

I think it's still thing? Haven't checked it recently though.

@benlesh
Copy link
Member

benlesh commented Dec 10, 2020

This issue came up at Google, I'm reopening it, although no one has been able to come up with a simple reproduction. :\

@benlesh benlesh reopened this Dec 10, 2020
@benlesh
Copy link
Member

benlesh commented Dec 10, 2020

I believe it started with this PR: #5619

cc @cartant

@benlesh
Copy link
Member

benlesh commented Dec 10, 2020

Actually... this isn't quite the same thing as what I was talking about... :\ Closing again. We'll need to file another issue.

@benlesh benlesh closed this as completed Dec 10, 2020
@amakhrov
Copy link

amakhrov commented Nov 8, 2021

(I know it's closed. And there is no open issue for this problem currently.)

I see this in our logs occasionally, in our Angular app. [email protected].
No idea how to reproduce. Mostly happens on Windows. Very rare anyway.

If I ever get more details, I'll file a new issue. But most probably I'm just gonna ignore it.

@MaximSagan
Copy link

Actually... this isn't quite the same thing as what I was talking about... :\ Closing again. We'll need to file another issue.

@benlesh Was another issue filed? This issue seems to be occurring in rxjs v7. (Can't reproduce just yet. Will update if I can)

@nanditsaini
Copy link

We are also facing the same issue and we have seen that it happens immediately after an "npm i" and then running our unit tests. Then after 1-2 times of executing our unit tests its stops comming

@rahcusa
Copy link

rahcusa commented Dec 12, 2022

I was encountering this while running marble tests in an angular project with the following dependencies:-
"rxjs": "~7.5.7",
"@angular/core": "~14.2.9",
"jasmine": "~4.5.0",
"karma-jasmine": "~5.1.0",

I resolved it by doing the following

  1. in test.ts, I added
import 'zone.js';
+ import 'zone.js/dist/zone-patch-rxjs'; // add zone-patch-rxjs to properly patch RxJS API
import 'zone.js/testing';
  1. in my .spec.ts, I organized it so that all subscriptions/subscriptions/observables were initialized inside testScheduler.run
import { TestScheduler } from 'rxjs/testing';

describe('MyReactiveClass', () => {
   let myClass: MyReactiveClass; // class that has observables we want to test
   let testScheduler;

   const init = () {
     myClass = new MyReactiveClass()
   };

  beforeEach(() => {
    testScheduler = new TestScheduler((actual, expected) => {
      expect(actual).toEqual(expected);
    });
  });
  
  it('should .....', () => {
    testScheduler.run(helpers => {
      init();
      const { expectObservable, cold } = helpers;
      // .... run marble tests
      // expectObservable(myClass.someObs).toBe(.....)
    });
  });
});


@arjun1607
Copy link

@nanditsaini @pshurygin @rahcusa what did you guys do for the flaky nature of the unit test. I am facing the same issue "Executing a cancelled action" in my jasmine tests for angular 16 application. Sometimes they fail and sometimes they pass.

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

No branches or pull requests

10 participants