Batch attachment download jobs
This commit is contained in:
parent
1b8be6a3d1
commit
86026bd66a
6 changed files with 54 additions and 7 deletions
|
@ -47,6 +47,7 @@ import { AttachmentDownloadSource } from '../sql/Interface';
|
||||||
import { drop } from '../util/drop';
|
import { drop } from '../util/drop';
|
||||||
import { getAttachmentCiphertextLength } from '../AttachmentCrypto';
|
import { getAttachmentCiphertextLength } from '../AttachmentCrypto';
|
||||||
import { safeParsePartial } from '../util/schemas';
|
import { safeParsePartial } from '../util/schemas';
|
||||||
|
import { createBatcher } from '../util/batcher';
|
||||||
|
|
||||||
export enum AttachmentDownloadUrgency {
|
export enum AttachmentDownloadUrgency {
|
||||||
IMMEDIATE = 'immediate',
|
IMMEDIATE = 'immediate',
|
||||||
|
@ -110,12 +111,27 @@ function getJobIdForLogging(job: CoreAttachmentDownloadJobType): string {
|
||||||
|
|
||||||
export class AttachmentDownloadManager extends JobManager<CoreAttachmentDownloadJobType> {
|
export class AttachmentDownloadManager extends JobManager<CoreAttachmentDownloadJobType> {
|
||||||
private visibleTimelineMessages: Set<string> = new Set();
|
private visibleTimelineMessages: Set<string> = new Set();
|
||||||
|
private saveJobsBatcher = createBatcher<AttachmentDownloadJobType>({
|
||||||
|
name: 'saveAttachmentDownloadJobs',
|
||||||
|
wait: 150,
|
||||||
|
maxSize: 1000,
|
||||||
|
processBatch: async jobs => {
|
||||||
|
await DataWriter.saveAttachmentDownloadJobs(jobs);
|
||||||
|
drop(this.maybeStartJobs());
|
||||||
|
},
|
||||||
|
});
|
||||||
private static _instance: AttachmentDownloadManager | undefined;
|
private static _instance: AttachmentDownloadManager | undefined;
|
||||||
override logPrefix = 'AttachmentDownloadManager';
|
override logPrefix = 'AttachmentDownloadManager';
|
||||||
|
|
||||||
static defaultParams: AttachmentDownloadManagerParamsType = {
|
static defaultParams: AttachmentDownloadManagerParamsType = {
|
||||||
markAllJobsInactive: DataWriter.resetAttachmentDownloadActive,
|
markAllJobsInactive: DataWriter.resetAttachmentDownloadActive,
|
||||||
saveJob: DataWriter.saveAttachmentDownloadJob,
|
saveJob: async (job, options) => {
|
||||||
|
if (options?.allowBatching) {
|
||||||
|
AttachmentDownloadManager._instance?.saveJobsBatcher.add(job);
|
||||||
|
} else {
|
||||||
|
await DataWriter.saveAttachmentDownloadJob(job);
|
||||||
|
}
|
||||||
|
},
|
||||||
removeJob: DataWriter.removeAttachmentDownloadJob,
|
removeJob: DataWriter.removeAttachmentDownloadJob,
|
||||||
getNextJobs: DataWriter.getNextAttachmentDownloadJobs,
|
getNextJobs: DataWriter.getNextAttachmentDownloadJobs,
|
||||||
runDownloadAttachmentJob,
|
runDownloadAttachmentJob,
|
||||||
|
@ -227,9 +243,14 @@ export class AttachmentDownloadManager extends JobManager<CoreAttachmentDownload
|
||||||
}
|
}
|
||||||
|
|
||||||
static async start(): Promise<void> {
|
static async start(): Promise<void> {
|
||||||
|
await AttachmentDownloadManager.saveBatchedJobs();
|
||||||
await AttachmentDownloadManager.instance.start();
|
await AttachmentDownloadManager.instance.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async saveBatchedJobs(): Promise<void> {
|
||||||
|
await AttachmentDownloadManager.instance.saveJobsBatcher.flushAndWait();
|
||||||
|
}
|
||||||
|
|
||||||
static async stop(): Promise<void> {
|
static async stop(): Promise<void> {
|
||||||
return AttachmentDownloadManager._instance?.stop();
|
return AttachmentDownloadManager._instance?.stop();
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,10 @@ export type JobManagerParamsType<
|
||||||
limit: number;
|
limit: number;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
}) => Promise<Array<JobType>>;
|
}) => Promise<Array<JobType>>;
|
||||||
saveJob: (job: JobType) => Promise<void>;
|
saveJob: (
|
||||||
|
job: JobType,
|
||||||
|
options?: { allowBatching?: boolean }
|
||||||
|
) => Promise<void>;
|
||||||
removeJob: (job: JobType) => Promise<void>;
|
removeJob: (job: JobType) => Promise<void>;
|
||||||
runJob: (
|
runJob: (
|
||||||
job: JobType,
|
job: JobType,
|
||||||
|
@ -190,7 +193,8 @@ export abstract class JobManager<CoreJobType> {
|
||||||
return { isAlreadyRunning: true };
|
return { isAlreadyRunning: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.params.saveJob(job);
|
// Allow batching of all saves except those that we will start immediately
|
||||||
|
await this.params.saveJob(job, { allowBatching: !options?.forceStart });
|
||||||
|
|
||||||
if (options?.forceStart) {
|
if (options?.forceStart) {
|
||||||
if (!this.enabled) {
|
if (!this.enabled) {
|
||||||
|
|
|
@ -110,6 +110,7 @@ import { loadAllAndReinitializeRedux } from '../allLoaders';
|
||||||
import { resetBackupMediaDownloadProgress } from '../../util/backupMediaDownload';
|
import { resetBackupMediaDownloadProgress } from '../../util/backupMediaDownload';
|
||||||
import { getEnvironment, isTestEnvironment } from '../../environment';
|
import { getEnvironment, isTestEnvironment } from '../../environment';
|
||||||
import { drop } from '../../util/drop';
|
import { drop } from '../../util/drop';
|
||||||
|
import { hasAttachmentDownloads } from '../../util/hasAttachmentDownloads';
|
||||||
|
|
||||||
const MAX_CONCURRENCY = 10;
|
const MAX_CONCURRENCY = 10;
|
||||||
|
|
||||||
|
@ -519,6 +520,8 @@ export class BackupImportStream extends Writable {
|
||||||
ourAci,
|
ourAci,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const attachmentDownloadJobPromises: Array<Promise<unknown>> = [];
|
||||||
|
|
||||||
// TODO (DESKTOP-7402): consider re-saving after updating the pending state
|
// TODO (DESKTOP-7402): consider re-saving after updating the pending state
|
||||||
for (const attributes of batch) {
|
for (const attributes of batch) {
|
||||||
const { editHistory } = attributes;
|
const { editHistory } = attributes;
|
||||||
|
@ -539,11 +542,16 @@ export class BackupImportStream extends Writable {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-await-in-loop
|
if (hasAttachmentDownloads(attributes)) {
|
||||||
await queueAttachmentDownloads(attributes, {
|
attachmentDownloadJobPromises.push(
|
||||||
source: AttachmentDownloadSource.BACKUP_IMPORT,
|
queueAttachmentDownloads(attributes, {
|
||||||
});
|
source: AttachmentDownloadSource.BACKUP_IMPORT,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
await Promise.all(attachmentDownloadJobPromises);
|
||||||
|
await AttachmentDownloadManager.saveBatchedJobs();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async saveCallHistory(
|
private async saveCallHistory(
|
||||||
|
|
|
@ -863,6 +863,7 @@ type WritableInterface = {
|
||||||
timestamp?: number;
|
timestamp?: number;
|
||||||
}) => Array<AttachmentDownloadJobType>;
|
}) => Array<AttachmentDownloadJobType>;
|
||||||
saveAttachmentDownloadJob: (job: AttachmentDownloadJobType) => void;
|
saveAttachmentDownloadJob: (job: AttachmentDownloadJobType) => void;
|
||||||
|
saveAttachmentDownloadJobs: (jobs: Array<AttachmentDownloadJobType>) => void;
|
||||||
resetAttachmentDownloadActive: () => void;
|
resetAttachmentDownloadActive: () => void;
|
||||||
removeAttachmentDownloadJob: (job: AttachmentDownloadJobType) => void;
|
removeAttachmentDownloadJob: (job: AttachmentDownloadJobType) => void;
|
||||||
removeAllBackupAttachmentDownloadJobs: () => void;
|
removeAllBackupAttachmentDownloadJobs: () => void;
|
||||||
|
|
|
@ -486,6 +486,7 @@ export const DataWriter: ServerWritableInterface = {
|
||||||
|
|
||||||
getNextAttachmentDownloadJobs,
|
getNextAttachmentDownloadJobs,
|
||||||
saveAttachmentDownloadJob,
|
saveAttachmentDownloadJob,
|
||||||
|
saveAttachmentDownloadJobs,
|
||||||
resetAttachmentDownloadActive,
|
resetAttachmentDownloadActive,
|
||||||
removeAttachmentDownloadJob,
|
removeAttachmentDownloadJob,
|
||||||
removeAllBackupAttachmentDownloadJobs,
|
removeAllBackupAttachmentDownloadJobs,
|
||||||
|
@ -5000,6 +5001,17 @@ function getNextAttachmentDownloadJobs(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function saveAttachmentDownloadJobs(
|
||||||
|
db: WritableDB,
|
||||||
|
jobs: Array<AttachmentDownloadJobType>
|
||||||
|
): void {
|
||||||
|
db.transaction(() => {
|
||||||
|
for (const job of jobs) {
|
||||||
|
saveAttachmentDownloadJob(db, job);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
function saveAttachmentDownloadJob(
|
function saveAttachmentDownloadJob(
|
||||||
db: WritableDB,
|
db: WritableDB,
|
||||||
job: AttachmentDownloadJobType
|
job: AttachmentDownloadJobType
|
||||||
|
|
|
@ -83,6 +83,7 @@ describe('AttachmentDownloadManager/JobManager', () => {
|
||||||
|
|
||||||
downloadManager = new AttachmentDownloadManager({
|
downloadManager = new AttachmentDownloadManager({
|
||||||
...AttachmentDownloadManager.defaultParams,
|
...AttachmentDownloadManager.defaultParams,
|
||||||
|
saveJob: DataWriter.saveAttachmentDownloadJob,
|
||||||
shouldHoldOffOnStartingQueuedJobs: isInCall,
|
shouldHoldOffOnStartingQueuedJobs: isInCall,
|
||||||
runDownloadAttachmentJob: runJob,
|
runDownloadAttachmentJob: runJob,
|
||||||
getRetryConfig: () => ({
|
getRetryConfig: () => ({
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue