question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How to clean up resources when subscriptions end?

See original GitHub issue

I’m submitting a…


[ ] Regression 
[ ] Bug report
[ ] Feature request
[x] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

Suppose there is a Subscription defined, which sets up an interval that polls a remote service every X seconds. I’m not sure how this interval could be cleared when the subscription is done, either via forced unsubscription from a client, or a disconnect of the underlying websocket.

I have looked through upstream graphql subscriptions for an answer but it seems unclear whether this is possible at all.

Expected behavior

Have a way to do cleanup when a subscription ends.

Minimal reproduction of the problem with instructions

@Subscription(returns => Something)
someSubscription() {
  setInterval(async () => {
      pubSub.publish('someSubscription', {
        someSubscription: (await fetchDataFromRemoteService())
      });
    }, 5000);
  return pubSub.asyncIterator('someSubscription');
}

If the client disappears, this interval would keep firing forever. With multiple clients, this would quickly end up in a huge memory leak and potential DoS on the remote service.

How would one clean up the interval? (or could be RxJS observable, or anything else)

What is the motivation / use case for changing the behavior?

Environment


Nest version: 6.0.1

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
andreialecucommented, Mar 31, 2019

Leaving this here as it may help someone:

// with-observable.ts
import { Observable } from 'rxjs';

export function withCancel<T>(
  asyncIterator: AsyncIterator<T | undefined>,
  onCancel: () => void,
): AsyncIterator<T | undefined> {
  return {
    ...asyncIterator,
    return() {
      onCancel();
      return asyncIterator.return
        ? asyncIterator.return()
        : Promise.resolve({ value: undefined, done: true });
    },
  };
}

interface PubSub {
  publish: (trigger: string, data: any) => void;
  asyncIterator: (trigger: string) => AsyncIterator<{}>;
}

export function withObservable<T>(
  observable: Observable<T>,
  pubSub: PubSub,
  trigger: string,
) {
  const subscription = observable.subscribe(data => {
    pubSub.publish(trigger, {
      [trigger]: data,
    });
  });

  return withCancel(pubSub.asyncIterator(trigger), () => {
    subscription.unsubscribe();
  });
}
  // usage
  @Subscription(returns => Something)
  public someSubscription() {
    return withObservable(this.changes$, pubSub, 'someSubscription');
  }

Your observable’s teardown logic will be called when subscriptions end.

1reaction
andreialecucommented, Mar 31, 2019

Yup, it’s custom, but I was expecting something built-in.

Everything seems to be abstracted in various ways with decorators already by Nest. So perhaps it could allow returning a RxJS Observable from the Subscription handler, and if an Observable is returned, wrap it in an AsyncIterable itself.

Basically turning this:

@Subscription(returns => Something)
  public someSubscription() {
    const subscription = this.changes$.subscribe(async data => {
      pubSub.publish('someSubscription', {
        someSubscription: data,
      });
    });

    const iterator = withCancel(pubSub.asyncIterator('someSubscription'), () => {
      subscription.unsubscribe();
    });

    return iterator;
  }

into this:

  @Subscription(returns => Something)
  public someSubscription() {
    return this.changes$;
  }

I feel it would enforce better practices and help with discoverability, because one would know that standard RxJS Observable teardown logic would be available.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Clean up your subscription - step by step tutorial from DevOps ...
Cleanup, Removing unnecessary resources from Microsoft Azure cloud. Don't pay if you don't use, step by step tutorial by DevOps Architect.
Read more >
Terminate active AWS resources that you no longer need
Open the AWS Management Console. Open the console for the service that contains the resources that you want to terminate (for example, Amazon ......
Read more >
Clean Up instructions at the end of the module to stop ...
In the Azure portal, select Resource groups on the far left. · From the list, select the resource group that you created. ·...
Read more >
Tips for keeping your Azure Subscriptions Clean
Automatically remove unused resources from your Azure subscription · 1. Tag resources to be cleaned up · 2. Create a script that cleans...
Read more >
How to clean up subscriptions in react components using ...
One of the most common bug in react component where developers forget to clean up resources properly after unmount. So how do i...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found