From 8a01932c0d02b119b3bacdc8f15246a0cde98001 Mon Sep 17 00:00:00 2001 From: Rando Luik Date: Fri, 29 May 2026 11:22:21 +0300 Subject: [PATCH 1/2] Pass initial error to subscription clients --- .../__tests__/graphql-subscriptions.spec.ts | 12 ++---- .../lib/services/graphql/graphql.service.ts | 42 +++++++++---------- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/packages/javascript-api/src/lib/services/graphql/__tests__/graphql-subscriptions.spec.ts b/packages/javascript-api/src/lib/services/graphql/__tests__/graphql-subscriptions.spec.ts index bc642763..f13e138a 100644 --- a/packages/javascript-api/src/lib/services/graphql/__tests__/graphql-subscriptions.spec.ts +++ b/packages/javascript-api/src/lib/services/graphql/__tests__/graphql-subscriptions.spec.ts @@ -901,19 +901,13 @@ describe('GraphQL subscriptions', () => { expect(subscriptionErrorSpy).toHaveBeenCalledWith< [QminderGraphQLError[]] >([ - { - message: 'Subscription failed after 5 retries', - errorType: 'ERROR', - }, - ] satisfies QminderGraphQLError[]); + { message: 'The maximum subscription limit of 100 has been reached' }, + ]); expect(subscription2ErrorSpy).toHaveBeenCalledWith< [QminderGraphQLError[]] >([ - { - message: 'Subscription failed after 5 retries', - errorType: 'ERROR', - }, + { message: 'The maximum subscription limit of 100 has been reached' }, ]); subscription.unsubscribe(); diff --git a/packages/javascript-api/src/lib/services/graphql/graphql.service.ts b/packages/javascript-api/src/lib/services/graphql/graphql.service.ts index 8d5ed614..92fdf09f 100644 --- a/packages/javascript-api/src/lib/services/graphql/graphql.service.ts +++ b/packages/javascript-api/src/lib/services/graphql/graphql.service.ts @@ -132,6 +132,7 @@ export class GraphqlService { | { readonly type: 'add'; readonly messageId: string; + readonly errors: QminderGraphQLError[]; } | { readonly type: 'remove'; @@ -142,27 +143,27 @@ export class GraphqlService { } >(); - private readonly retryableErroredSubscriptionsMessageIds$ = + private readonly retryableErroredSubscriptions$ = this.retryableErroredSubscriptionsAction$.pipe( - scan((messageIds, action) => { - const result = new Set(messageIds); + scan((subscriptions, action) => { + const result = new Map(subscriptions); switch (action.type) { case 'add': - return result.add(action.messageId); + return result.set(action.messageId, action.errors); case 'remove': result.delete(action.messageId); return result; case 'clear': - return new Set(); + return new Map(); } - }, new Set()), - startWith(new Set()), + }, new Map()), + startWith(new Map()), shareReplay(1), ); private readonly haveAnyRetryableSubscriptionsErrored$ = - this.retryableErroredSubscriptionsMessageIds$.pipe( + this.retryableErroredSubscriptions$.pipe( map(({ size }) => !!size), distinctUntilChanged(), ); @@ -193,7 +194,7 @@ export class GraphqlService { shareReplay(1), ); - this.retryableErroredSubscriptionsMessageIds$.subscribe(); + this.retryableErroredSubscriptions$.subscribe(); } /** @@ -586,6 +587,7 @@ export class GraphqlService { this.retryableErroredSubscriptionsAction$.next({ type: 'add', messageId: message.id, + errors, }); if ( @@ -746,29 +748,27 @@ export class GraphqlService { private failErroredSubscriptions(): void { this.logger.error( - `Errored subscriptions retry limit (${RETRYABLE_ERRORED_SUBSCRIPTIONS_RETRY_LIMIT}) reached, giving up`, + `Errored subscriptions retry limit (${RETRYABLE_ERRORED_SUBSCRIPTIONS_RETRY_LIMIT}) reached. Giving up after ${this.retryableErroredSubscriptionsRetryCount} retries`, ); - this.retryableErroredSubscriptionsMessageIds$ + this.retryableErroredSubscriptions$ .pipe(take(1)) - .subscribe((messageIds) => { - for (const messageId of messageIds) { + .subscribe((subscriptions) => { + for (const [messageId, errors] of subscriptions) { const subscriber = this.messagesSubscribers.get(messageId); this.cleanUpSubscription(messageId); - subscriber?.error([ - { - message: `Subscription failed after ${this.retryableErroredSubscriptionsRetryCount} retries`, - errorType: 'ERROR', - }, - ] satisfies QminderGraphQLError[]); + subscriber?.error(errors); } }); } private retryErroredSubscriptions(): void { - this.retryableErroredSubscriptionsMessageIds$ - .pipe(take(1)) + this.retryableErroredSubscriptions$ + .pipe( + take(1), + map((subscriptions) => subscriptions.keys()), + ) .subscribe((messageIds) => { for (const messageId of messageIds) { const subscription = this.subscriptions.find( From bd1eab22a8f5889c00ec02323ed995e43b2ea3de Mon Sep 17 00:00:00 2001 From: Rando Luik Date: Fri, 29 May 2026 11:56:08 +0300 Subject: [PATCH 2/2] Improve error message --- .../src/lib/services/graphql/graphql.service.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/javascript-api/src/lib/services/graphql/graphql.service.ts b/packages/javascript-api/src/lib/services/graphql/graphql.service.ts index 92fdf09f..48e343ec 100644 --- a/packages/javascript-api/src/lib/services/graphql/graphql.service.ts +++ b/packages/javascript-api/src/lib/services/graphql/graphql.service.ts @@ -736,7 +736,9 @@ export class GraphqlService { const delay = calculateRandomizedExponentialBackoffTime(retryCount); this.logger.info( - `Retry (${retryCount}) errored subscriptions in ${delay.toFixed(0)}ms`, + `Retry (retry count: ${retryCount}) errored subscriptions in ${delay.toFixed( + 0, + )}ms`, ); this.retryableErroredSubscriptionsRetryTimeout = setTimeout(() => {