Description
more of a question...
in the implementation of subscriptions, is there a mechanism for pruning old subscriptions? While front ends SHOULD unsubscribe, often they do not.
Here is some rough code from chatGPT, but short of reimplementing subscriptions, I don't quite see how to integrate into the nestjs-query framework.
import { Resolver, Subscription } from '@nestjs/graphql';
import { PubSub } from 'graphql-subscriptions';
import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
const pubSub = new PubSub();
@Injectable()
@Resolver()
export class SubscriptionsResolver implements OnModuleInit, OnModuleDestroy {
private activeSubscriptions = new Map<string, { lastActive: Date }>();
private readonly CLEANUP_INTERVAL = 60000; // 1 minute
private readonly STALE_TIMEOUT = 300000; // 5 minutes
private cleanupIntervalId: NodeJS.Timeout;
onModuleInit() {
// Start the periodic cleanup task
this.cleanupIntervalId = setInterval(() => this.cleanUpStaleSubscriptions(), this.CLEANUP_INTERVAL);
}
onModuleDestroy() {
// Clear the cleanup task when the module is destroyed
clearInterval(this.cleanupIntervalId);
}
@Subscription(() => String, {
resolve: (payload) => payload.message,
filter: (payload, variables, context) => {
// Optionally, apply filtering logic based on the payload or context
return true;
},
})
subscribeToMessage() {
const subscriptionId = this.generateSubscriptionId(); // Define how you want to generate subscription IDs
this.trackSubscription(subscriptionId);
return pubSub.asyncIterator('message');
}
// Track subscriptions with timestamps
private trackSubscription(subscriptionId: string) {
const now = new Date();
this.activeSubscriptions.set(subscriptionId, { lastActive: now });
console.log(`Subscription ${subscriptionId} added`);
}
// Mark a subscription as active when an event is received
private updateSubscriptionActivity(subscriptionId: string) {
const now = new Date();
if (this.activeSubscriptions.has(subscriptionId)) {
this.activeSubscriptions.get(subscriptionId).lastActive = now;
console.log(`Subscription ${subscriptionId} updated`);
}
}
// Clean up stale subscriptions that haven't been active for a while
private cleanUpStaleSubscriptions() {
const now = new Date();
this.activeSubscriptions.forEach((value, subscriptionId) => {
if (now.getTime() - value.lastActive.getTime() > this.STALE_TIMEOUT) {
// Unsubscribe from stale subscription
this.activeSubscriptions.delete(subscriptionId);
console.log(`Subscription ${subscriptionId} removed due to inactivity`);
}
});
}
// Simulate message publishing for testing
publishMessage() {
pubSub.publish('message', { message: 'Hello World' });
}
// Dummy function for generating subscription IDs
private generateSubscriptionId(): string {
return Math.random().toString(36).substring(2, 15);
}
}
The periodic task is set up using setInterval in the onModuleInit method to run every 1 minute (CLEANUP_INTERVAL). The cleanUpStaleSubscriptions() method removes any subscriptions that have been inactive for more than the timeout (STALE_TIMEOUT).
This code provides a basic implementation of tracking subscriptions and cleaning up stale ones. You can adjust the timeout intervals or expand this logic to handle more advanced cases, like managing user-specific subscriptions or more complex payloads.
so.. is something implemented that does this already in the framework, and if not, is there an elegant approach you could recommend? Or should this become a feature request?