1
|
{"version":3,"file":"scheduler.js","names":["utils","_interopRequireWildcard","require","_logger","_event","_httpApi","_getRequireWildcardCache","nodeInterop","WeakMap","cacheBabelInterop","cacheNodeInterop","obj","__esModule","default","cache","has","get","newObj","hasPropertyDescriptor","Object","defineProperty","getOwnPropertyDescriptor","key","prototype","hasOwnProperty","call","desc","set","DEBUG","MatrixScheduler","RETRY_BACKOFF_RATELIMIT","event","attempts","err","httpStatus","ConnectionError","name","waitTime","data","retry_after_ms","Math","pow","QUEUE_MESSAGES","getType","EventType","RoomMessage","hasAssociation","constructor","retryAlgorithm","queueAlgorithm","_defineProperty2","queueName","peekNextEvent","disableQueue","debuglog","queues","length","Promise","resolve","then","procFn","res","removeNextEvent","getId","defer","processQueue","waitTimeMs","clearQueue","setTimeout","getQueueForEvent","map","removeEventFromQueue","removed","removeElement","element","setProcessFunction","fn","startProcessingQueues","queueEvent","push","promise","keys","filter","activeQueues","indexOf","forEach","index","splice","reject","queue","Array","isArray","undefined","shift","exports","args","logger","log"],"sources":["../src/scheduler.ts"],"sourcesContent":["/*\nCopyright 2015 - 2021 The Matrix.org Foundation C.I.C.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n/**\n * This is an internal module which manages queuing, scheduling and retrying\n * of requests.\n */\nimport * as utils from \"./utils\";\nimport { logger } from \"./logger\";\nimport { MatrixEvent } from \"./models/event\";\nimport { EventType } from \"./@types/event\";\nimport { IDeferred } from \"./utils\";\nimport { ConnectionError, MatrixError } from \"./http-api\";\nimport { ISendEventResponse } from \"./@types/requests\";\n\nconst DEBUG = false; // set true to enable console logging.\n\ninterface IQueueEntry<T> {\n event: MatrixEvent;\n defer: IDeferred<T>;\n attempts: number;\n}\n\n/**\n * The function to invoke to process (send) events in the queue.\n * @param event - The event to send.\n * @returns Resolved/rejected depending on the outcome of the request.\n */\ntype ProcessFunction<T> = (event: MatrixEvent) => Promise<T>;\n\n// eslint-disable-next-line camelcase\nexport class MatrixScheduler<T = ISendEventResponse> {\n /**\n * Retries events up to 4 times using exponential backoff. This produces wait\n * times of 2, 4, 8, and 16 seconds (30s total) after which we give up. If the\n * failure was due to a rate limited request, the time specified in the error is\n * waited before being retried.\n * @param attempts - Number of attempts that have been made, including the one that just failed (ie. starting at 1)\n * @see retryAlgorithm\n */\n // eslint-disable-next-line @typescript-eslint/naming-convention\n public static RETRY_BACKOFF_RATELIMIT(event: MatrixEvent | null, attempts: number, err: MatrixError): number {\n if (err.httpStatus === 400 || err.httpStatus === 403 || err.httpStatus === 401) {\n // client error; no amount of retrying with save you now.\n return -1;\n }\n if (err instanceof ConnectionError) {\n return -1;\n }\n\n // if event that we are trying to send is too large in any way then retrying won't help\n if (err.name === \"M_TOO_LARGE\") {\n return -1;\n }\n\n if (err.name === \"M_LIMIT_EXCEEDED\") {\n const waitTime = err.data.retry_after_ms;\n if (waitTime > 0) {\n return waitTime;\n }\n }\n if (attempts > 4) {\n return -1; // give up\n }\n return 1000 * Math.pow(2, attempts);\n }\n\n /**\n * Queues `m.room.message` events and lets other events continue\n * concurrently.\n * @see queueAlgorithm\n */\n // eslint-disable-next-line @typescript-eslint/naming-convention\n public static QUEUE_MESSAGES(event: MatrixEvent): string | null {\n // enqueue messages or events that associate with another event (redactions and relations)\n if (event.getType() === EventType.RoomMessage || event.hasAssociation()) {\n // put these events in the 'message' queue.\n return \"message\";\n }\n // allow all other events continue concurrently.\n return null;\n }\n\n // queueName: [{\n // event: MatrixEvent, // event to send\n // defer: Deferred, // defer to resolve/reject at the END of the retries\n // attempts: Number // number of times we've called processFn\n // }, ...]\n private readonly queues: Record<string, IQueueEntry<T>[]> = {};\n private activeQueues: string[] = [];\n private procFn: ProcessFunction<T> | null = null;\n\n /**\n * Construct a scheduler for Matrix. Requires\n * {@link MatrixScheduler#setProcessFunction} to be provided\n * with a way of processing events.\n * @param retryAlgorithm - Optional. The retry\n * algorithm to apply when determining when to try to send an event again.\n * Defaults to {@link MatrixScheduler.RETRY_BACKOFF_RATELIMIT}.\n * @param queueAlgorithm - Optional. The queuing\n * algorithm to apply when determining which events should be sent before the\n * given event. Defaults to {@link MatrixScheduler.QUEUE_MESSAGES}.\n */\n public constructor(\n /**\n * The retry algorithm to apply when retrying events. To stop retrying, return\n * `-1`. If this event was part of a queue, it will be removed from\n * the queue.\n * @param event - The event being retried.\n * @param attempts - The number of failed attempts. This will always be \\>= 1.\n * @param err - The most recent error message received when trying\n * to send this event.\n * @returns The number of milliseconds to wait before trying again. If\n * this is 0, the request will be immediately retried. If this is\n * `-1`, the event will be marked as\n * {@link EventStatus.NOT_SENT} and will not be retried.\n */\n public readonly retryAlgorithm = MatrixScheduler.RETRY_BACKOFF_RATELIMIT,\n /**\n * The queuing algorithm to apply to events. This function must be idempotent as\n * it may be called multiple times with the same event. All queues created are\n * serviced in a FIFO manner. To send the event ASAP, return `null`\n * which will not put this event in a queue. Events that fail to send that form\n * part of a queue will be removed from the queue and the next event in the\n * queue will be sent.\n * @param event - The event to be sent.\n * @returns The name of the queue to put the event into. If a queue with\n * this name does not exist, it will be created. If this is `null`,\n * the event is not put into a queue and will be sent concurrently.\n */\n public readonly queueAlgorithm = MatrixScheduler.QUEUE_MESSAGES,\n ) {}\n\n /**\n * Retrieve a queue based on an event. The event provided does not need to be in\n * the queue.\n * @param event - An event to get the queue for.\n * @returns A shallow copy of events in the queue or null.\n * Modifying this array will not modify the list itself. Modifying events in\n * this array <i>will</i> modify the underlying event in the queue.\n * @see MatrixScheduler.removeEventFromQueue To remove an event from the queue.\n */\n public getQueueForEvent(event: MatrixEvent): MatrixEvent[] | null {\n const name = this.queueAlgorithm(event);\n if (!name || !this.queues[name]) {\n return null;\n }\n return this.queues[name].map(function (obj) {\n return obj.event;\n });\n }\n\n /**\n * Remove this event from the queue. The event is equal to another event if they\n * have the same ID returned from event.getId().\n * @param event - The event to remove.\n * @returns True if this event was removed.\n */\n public removeEventFromQueue(event: MatrixEvent): boolean {\n const name = this.queueAlgorithm(event);\n if (!name || !this.queues[name]) {\n return false;\n }\n let removed = false;\n utils.removeElement(this.queues[name], (element) => {\n if (element.event.getId() === event.getId()) {\n // XXX we should probably reject the promise?\n // https://github.com/matrix-org/matrix-js-sdk/issues/496\n removed = true;\n return true;\n }\n return false;\n });\n return removed;\n }\n\n /**\n * Set the process function. Required for events in the queue to be processed.\n * If set after events have been added to the queue, this will immediately start\n * processing them.\n * @param fn - The function that can process events\n * in the queue.\n */\n public setProcessFunction(fn: ProcessFunction<T>): void {\n this.procFn = fn;\n this.startProcessingQueues();\n }\n\n /**\n * Queue an event if it is required and start processing queues.\n * @param event - The event that may be queued.\n * @returns A promise if the event was queued, which will be\n * resolved or rejected in due time, else null.\n */\n public queueEvent(event: MatrixEvent): Promise<T> | null {\n const queueName = this.queueAlgorithm(event);\n if (!queueName) {\n return null;\n }\n // add the event to the queue and make a deferred for it.\n if (!this.queues[queueName]) {\n this.queues[queueName] = [];\n }\n const defer = utils.defer<T>();\n this.queues[queueName].push({\n event: event,\n defer: defer,\n attempts: 0,\n });\n debuglog(\"Queue algorithm dumped event %s into queue '%s'\", event.getId(), queueName);\n this.startProcessingQueues();\n return defer.promise;\n }\n\n private startProcessingQueues(): void {\n if (!this.procFn) return;\n // for each inactive queue with events in them\n Object.keys(this.queues)\n .filter((queueName) => {\n return this.activeQueues.indexOf(queueName) === -1 && this.queues[queueName].length > 0;\n })\n .forEach((queueName) => {\n // mark the queue as active\n this.activeQueues.push(queueName);\n // begin processing the head of the queue\n debuglog(\"Spinning up queue: '%s'\", queueName);\n this.processQueue(queueName);\n });\n }\n\n private processQueue = (queueName: string): void => {\n // get head of queue\n const obj = this.peekNextEvent(queueName);\n if (!obj) {\n this.disableQueue(queueName);\n return;\n }\n debuglog(\"Queue '%s' has %s pending events\", queueName, this.queues[queueName].length);\n // fire the process function and if it resolves, resolve the deferred. Else\n // invoke the retry algorithm.\n\n // First wait for a resolved promise, so the resolve handlers for\n // the deferred of the previously sent event can run.\n // This way enqueued relations/redactions to enqueued events can receive\n // the remove id of their target before being sent.\n Promise.resolve()\n .then(() => {\n return this.procFn!(obj.event);\n })\n .then(\n (res) => {\n // remove this from the queue\n this.removeNextEvent(queueName);\n debuglog(\"Queue '%s' sent event %s\", queueName, obj.event.getId());\n obj.defer.resolve(res);\n // keep processing\n this.processQueue(queueName);\n },\n (err) => {\n obj.attempts += 1;\n // ask the retry algorithm when/if we should try again\n const waitTimeMs = this.retryAlgorithm(obj.event, obj.attempts, err);\n debuglog(\n \"retry(%s) err=%s event_id=%s waitTime=%s\",\n obj.attempts,\n err,\n obj.event.getId(),\n waitTimeMs,\n );\n if (waitTimeMs === -1) {\n // give up (you quitter!)\n debuglog(\"Queue '%s' giving up on event %s\", queueName, obj.event.getId());\n // remove this from the queue\n this.clearQueue(queueName, err);\n } else {\n setTimeout(this.processQueue, waitTimeMs, queueName);\n }\n },\n );\n };\n\n private disableQueue(queueName: string): void {\n // queue is empty. Mark as inactive and stop recursing.\n const index = this.activeQueues.indexOf(queueName);\n if (index >= 0) {\n this.activeQueues.splice(index, 1);\n }\n debuglog(\"Stopping queue '%s' as it is now empty\", queueName);\n }\n\n private clearQueue(queueName: string, err: unknown): void {\n debuglog(\"clearing queue '%s'\", queueName);\n let obj: IQueueEntry<T> | undefined;\n while ((obj = this.removeNextEvent(queueName))) {\n obj.defer.reject(err);\n }\n this.disableQueue(queueName);\n }\n\n private peekNextEvent(queueName: string): IQueueEntry<T> | undefined {\n const queue = this.queues[queueName];\n if (!Array.isArray(queue)) {\n return undefined;\n }\n return queue[0];\n }\n\n private removeNextEvent(queueName: string): IQueueEntry<T> | undefined {\n const queue = this.queues[queueName];\n if (!Array.isArray(queue)) {\n return undefined;\n }\n return queue.shift();\n }\n}\n\n/* istanbul ignore next */\nfunction debuglog(...args: any[]): void {\n if (DEBUG) {\n logger.log(...args);\n }\n}\n"],"mappings":"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"}
|