Skip to content

Give access to send errors for to-device message sending using the queue (sendQueue) #4793

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

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions src/ToDeviceMessageQueue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,14 @@
this.client.removeListener(ClientEvent.Sync, this.onResumedSync);
}

public async queueBatch(batch: ToDeviceBatch): Promise<void> {
/**
* queues a batch of to-device messages for sending. The batch is split into
* smaller batches of size MAX_BATCH_SIZE, and each batch is given a unique
* transaction ID.
* @param batch the total (not split) batch of to-device messages.
* @param sendCallback a callback that is called once all batches are sent.
*/
public async queueBatch(batch: ToDeviceBatch, sendCallback?: (result: Error | undefined) => void): Promise<void> {
const batches: ToDeviceBatchWithTxnId[] = [];
for (let i = 0; i < batch.batch.length; i += MAX_BATCH_SIZE) {
const batchWithTxnId = {
Expand All @@ -74,10 +81,15 @@
}

await this.client.store.saveToDeviceBatches(batches);
this.sendQueue();
this.sendQueue().then(sendCallback);
}

public sendQueue = async (): Promise<void> => {
/**
* sends the queues to device messages currently saved in client.store.
* @returns resolves to undefined if the queue was sent successfully, or an error if
* the queue could not be sent.
*/
public sendQueue = async (): Promise<Error | undefined> => {
if (this.retryTimeout !== null) clearTimeout(this.retryTimeout);
this.retryTimeout = null;

Expand Down Expand Up @@ -114,13 +126,14 @@
} else {
logger.info("Automatic retry limit reached for to-device messages.");
}
return;
return Error("max to devices retries reached");
}

logger.info(`Failed to send batch of to-device messages. Will retry in ${retryDelay}ms`, e);
this.retryTimeout = setTimeout(this.sendQueue, retryDelay);
} finally {
this.sending = false;
return undefined;

Check failure on line 136 in src/ToDeviceMessageQueue.ts

View workflow job for this annotation

GitHub Actions / ESLint

Unsafe usage of ReturnStatement
}
};

Expand Down
37 changes: 30 additions & 7 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,16 @@
type GroupCallEventHandlerEventHandlerMap,
} from "./webrtc/groupCallEventHandler.ts";
import * as utils from "./utils.ts";
import { deepCompare, defer, noUnsafeEventProps, type QueryDict, replaceParam, safeSet, sleep } from "./utils.ts";
import {
deepCompare,
defer,
MapWithDefault,
noUnsafeEventProps,
type QueryDict,
replaceParam,
safeSet,
sleep,
} from "./utils.ts";
import { Direction, EventTimeline } from "./models/event-timeline.ts";
import { type IActionsObject, PushProcessor } from "./pushprocessor.ts";
import { AutoDiscovery, type AutoDiscoveryAction } from "./autodiscovery.ts";
Expand Down Expand Up @@ -7948,7 +7957,8 @@
* @param eventType - The type of event to send
* @param devices - The list of devices to send the event to.
* @param payload - The payload to send. This will be encrypted.
* @returns Promise which resolves once queued there is no error feedback when sending fails.
* @returns Promise which resolves once send there. Can be rejected with an error if sending fails
* Sending will retry automatically but there is a Max retries limit.
*/
public async encryptAndSendToDevice(
eventType: string,
Expand All @@ -7960,9 +7970,20 @@
}
const batch = await this.cryptoBackend.encryptToDeviceMessages(eventType, devices, payload);

// TODO The batch mechanism removes all possibility to get error feedbacks..
// We might want instead to do the API call directly and pass the errors back.
await this.queueToDevice(batch);
const contentMap: MapWithDefault<string, Map<string, ToDevicePayload>> = new MapWithDefault(() => new Map());
for (const item of batch.batch) {
contentMap.getOrCreate(item.userId).set(item.deviceId, item.payload);
}

return new Promise<void>((resolve, reject) => {
this.queueToDevice(batch, (result) => {
if (result === undefined) {
resolve;

Check failure on line 7981 in src/client.ts

View workflow job for this annotation

GitHub Actions / ESLint

Expected an assignment or function call and instead saw an expression
} else if (result) {
reject(result);
}
});
});
}

/**
Expand All @@ -7971,9 +7992,11 @@
* batches for sending and stored in the store so they can be retried
* later if they fail to send. Retries will happen automatically.
* @param batch - The to-device messages to send
* @param sendCallback - Optional callback to call when the batch is sent
* @returns Promise which resolves once the batch is queued.
*/
public queueToDevice(batch: ToDeviceBatch): Promise<void> {
return this.toDeviceMessageQueue.queueBatch(batch);
public queueToDevice(batch: ToDeviceBatch, sendCallback?: (result: Error | undefined) => void): Promise<void> {
return this.toDeviceMessageQueue.queueBatch(batch, sendCallback);
}

/**
Expand Down
Loading