Running a method defined in an injected service on a Glimmer components teardown

I’m struggling to find a proper pattern to stop a poller which is injected as a service in the teardown of a glimmer component. The poller in question just makes a network call every few seconds until a condition is met using the later function from @ember/runloop . Ideally just before the component is dismounted, the component should run the pollers’s stop function. I tried using the willDestroy hook as follows.

import Service from '@ember/service';

export default class Poller extends Service {
  start() {
     // some logic to start polling
  }

  stop(){
     // some logic to end polling
   }
}
import Component from '@glimmer/component';

export default class SomeComponent extends Component {
   @service poller

   contructor(){
      super()
      this.poller.start()
   }

   willDestroy() { 
      this.poller.stop(); 
   }
}

This works when I run the app but when I run my tests I get Can not call ".lookup" after the owner has been destroyed I could wrap the whole thing in a try...catch... block but I’m not sure if there is a better pattern.

I’m curious to know if there is a better pattern out there to run a method from a service on willDestroy of a glimmer component

This looks correct. Perhaps the poller doesn’t really cancel its final request correctly when you call stop()? For example, if a fetch was already running when you call stop(), is there code in place that will guarantee the poller won’t try to do anything with the response when it finally arrives?

Can you tell who is trying to call .lookup and what they’re looking up? See if you can break in that stack trace to see.

1 Like

Hey! Thank you for your response. After posting here, I tried the same on an empty ember project @v3.26.0 and I was not able to reproduce it!

So something in my repo, I’m not sure what it is yet, is causing the owner to be destroyed during acceptance testing and that is causing the service lookup to fail with: Can not call ".lookup" after the owner has been destroyed

I was also able to confirm that this.isDestroying and this.isDestroyed were already true when willDestroy was running.

I short circuited the service lookup by adding the following to the willDestroy

  willDestroy(...args) {
    super.willDestroy(...args);

    if (getOwner(this).isDestroyed) {
      return;
    }

    this.poller.stop();
  }
}

It’s a temporary solution but it worked.

I’m developing on a big monorepo with ember-engines so I’m unfortunately, I’m not entirely sure where this bug might be originating from.