Compare commits

...

4 Commits

Author SHA1 Message Date
Tom Moor e92500dd85 tsc 2025-04-28 21:38:42 -04:00
codegen-sh[bot] 1acec2502e Applied automatic fixes 2025-04-29 00:27:06 +00:00
Tom Moor c42ce87309 Delete update_task_schedule.sh 2025-04-28 20:25:32 -04:00
codegen-sh[bot] cab5dcef6a Update task scheduling to use instance method 2025-04-29 00:23:43 +00:00
28 changed files with 88 additions and 59 deletions
@@ -66,6 +66,6 @@ export class NotionImportsProcessor extends ImportsProcessor<IntegrationService.
protected async scheduleTask(
importTask: ImportTask<IntegrationService.Notion>
): Promise<void> {
await NotionAPIImportTask.schedule({ importTaskId: importTask.id });
await new NotionAPIImportTask().schedule({ importTaskId: importTask.id });
}
}
@@ -77,7 +77,7 @@ export default class NotionAPIImportTask extends APIImportTask<IntegrationServic
protected async scheduleNextTask(
importTask: ImportTask<IntegrationService.Notion>
) {
await NotionAPIImportTask.schedule({ importTaskId: importTask.id });
await new NotionAPIImportTask().schedule({ importTaskId: importTask.id });
return;
}
@@ -29,8 +29,12 @@ describe("WebhookProcessor", () => {
await processor.perform(event);
expect(DeliverWebhookTask.schedule).toHaveBeenCalled();
expect(DeliverWebhookTask.schedule).toHaveBeenCalledWith({
expect(
jest.mocked(DeliverWebhookTask.prototype.schedule)
).toHaveBeenCalled();
expect(
jest.mocked(DeliverWebhookTask.prototype.schedule)
).toHaveBeenCalledWith({
event,
subscriptionId: subscription.id,
});
@@ -53,7 +57,9 @@ describe("WebhookProcessor", () => {
await processor.perform(event);
expect(DeliverWebhookTask.schedule).toHaveBeenCalledTimes(0);
expect(
jest.mocked(DeliverWebhookTask.prototype.schedule)
).toHaveBeenCalledTimes(0);
});
it("it schedules a delivery for the event for each subscription", async () => {
@@ -79,13 +85,21 @@ describe("WebhookProcessor", () => {
await processor.perform(event);
expect(DeliverWebhookTask.schedule).toHaveBeenCalled();
expect(DeliverWebhookTask.schedule).toHaveBeenCalledTimes(2);
expect(DeliverWebhookTask.schedule).toHaveBeenCalledWith({
expect(
jest.mocked(DeliverWebhookTask.prototype.schedule)
).toHaveBeenCalled();
expect(
jest.mocked(DeliverWebhookTask.prototype.schedule)
).toHaveBeenCalledTimes(2);
expect(
jest.mocked(DeliverWebhookTask.prototype.schedule)
).toHaveBeenCalledWith({
event,
subscriptionId: subscription.id,
});
expect(DeliverWebhookTask.schedule).toHaveBeenCalledWith({
expect(
jest.mocked(DeliverWebhookTask.prototype.schedule)
).toHaveBeenCalledWith({
event,
subscriptionId: subscriptionTwo.id,
});
@@ -24,7 +24,10 @@ export default class WebhookProcessor extends BaseProcessor {
await Promise.all(
applicableSubscriptions.map((subscription) =>
DeliverWebhookTask.schedule({ event, subscriptionId: subscription.id })
new DeliverWebhookTask().schedule({
event,
subscriptionId: subscription.id,
})
)
);
}
+1 -1
View File
@@ -24,7 +24,7 @@ type Props = {
/** Position of moved document within document structure */
index?: number;
/** The IP address of the user moving the document */
ip: string;
ip: string | null;
/** The database transaction to run within */
transaction?: Transaction;
};
@@ -4,9 +4,11 @@ import DeleteAttachmentTask from "@server/queues/tasks/DeleteAttachmentTask";
import { buildAttachment, buildDocument } from "@server/test/factories";
import documentPermanentDeleter from "./documentPermanentDeleter";
jest.mock("@server/queues/tasks/DeleteAttachmentTask", () => ({
schedule: jest.fn(),
}));
jest.mock("@server/queues/tasks/DeleteAttachmentTask");
beforeEach(() => {
jest.resetAllMocks();
});
describe("documentPermanentDeleter", () => {
it("should destroy documents", async () => {
@@ -60,7 +62,9 @@ describe("documentPermanentDeleter", () => {
await document.save();
const countDeletedDoc = await documentPermanentDeleter([document]);
expect(countDeletedDoc).toEqual(1);
expect(DeleteAttachmentTask.schedule).toHaveBeenCalledTimes(2);
expect(
jest.mocked(DeleteAttachmentTask.prototype.schedule)
).toHaveBeenCalledTimes(2);
expect(
await Document.unscoped().count({
where: {
+1 -1
View File
@@ -67,7 +67,7 @@ export default async function documentPermanentDeleter(documents: Document[]) {
"commands",
`Attachment ${attachmentId} scheduled for deletion`
);
await DeleteAttachmentTask.schedule({
await new DeleteAttachmentTask().schedule({
attachmentId,
teamId: document.teamId,
});
+1 -1
View File
@@ -56,5 +56,5 @@ export default async function userSuspender({
}
);
await CleanupDemotedUserTask.schedule({ userId: user.id });
await new CleanupDemotedUserTask().schedule({ userId: user.id });
}
+1 -1
View File
@@ -408,7 +408,7 @@ class Team extends ParanoidModel<
});
if (attachment) {
await DeleteAttachmentTask.schedule({
await new DeleteAttachmentTask().schedule({
attachmentId: attachment.id,
teamId: model.id,
});
+1 -1
View File
@@ -717,7 +717,7 @@ class User extends ParanoidModel<
});
if (attachment) {
await DeleteAttachmentTask.schedule({
await new DeleteAttachmentTask().schedule({
attachmentId: attachment.id,
teamId: model.teamId,
});
+2 -2
View File
@@ -17,7 +17,7 @@ export default class AvatarProcessor extends BaseProcessor {
});
if (user.avatarUrl) {
await UploadUserAvatarTask.schedule({
await new UploadUserAvatarTask().schedule({
userId: event.userId,
avatarUrl: user.avatarUrl,
});
@@ -30,7 +30,7 @@ export default class AvatarProcessor extends BaseProcessor {
});
if (team.avatarUrl) {
await UploadTeamAvatarTask.schedule({
await new UploadTeamAvatarTask().schedule({
teamId: event.teamId,
avatarUrl: team.avatarUrl,
});
@@ -12,7 +12,7 @@ export default class CollectionsProcessor extends BaseProcessor {
];
async perform(event: CollectionEvent) {
await DetachDraftsFromCollectionTask.schedule({
await new DetachDraftsFromCollectionTask().schedule({
collectionId: event.collectionId,
actorId: event.actorId,
ip: event.ip,
@@ -27,7 +27,7 @@ export default class DocumentSubscriptionProcessor extends BaseProcessor {
async perform(event: ReceivedEvent) {
switch (event.name) {
case "collections.remove_user": {
await CollectionSubscriptionRemoveUserTask.schedule(event);
await new CollectionSubscriptionRemoveUserTask().schedule(event);
return;
}
@@ -35,7 +35,7 @@ export default class DocumentSubscriptionProcessor extends BaseProcessor {
return this.handleRemoveGroupFromCollection(event);
case "documents.remove_user": {
await DocumentSubscriptionRemoveUserTask.schedule(event);
await new DocumentSubscriptionRemoveUserTask().schedule(event);
return;
}
@@ -57,11 +57,11 @@ export default class DocumentSubscriptionProcessor extends BaseProcessor {
async (groupUsers) => {
await Promise.all(
groupUsers.map((groupUser) =>
CollectionSubscriptionRemoveUserTask.schedule({
new CollectionSubscriptionRemoveUserTask().schedule({
...event,
name: "collections.remove_user",
userId: groupUser.userId,
})
} as CollectionUserEvent)
)
);
}
@@ -79,11 +79,11 @@ export default class DocumentSubscriptionProcessor extends BaseProcessor {
async (groupUsers) => {
await Promise.all(
groupUsers.map((groupUser) =>
DocumentSubscriptionRemoveUserTask.schedule({
new DocumentSubscriptionRemoveUserTask().schedule({
...event,
name: "documents.remove_user",
userId: groupUser.userId,
})
} as DocumentUserEvent)
)
);
}
@@ -20,12 +20,12 @@ export default class FileOperationCreatedProcessor extends BaseProcessor {
if (fileOperation.type === FileOperationType.Import) {
switch (fileOperation.format) {
case FileOperationFormat.MarkdownZip:
await ImportMarkdownZipTask.schedule({
await new ImportMarkdownZipTask().schedule({
fileOperationId: event.modelId,
});
break;
case FileOperationFormat.JSON:
await ImportJSONTask.schedule({
await new ImportJSONTask().schedule({
fileOperationId: event.modelId,
});
break;
@@ -36,17 +36,17 @@ export default class FileOperationCreatedProcessor extends BaseProcessor {
if (fileOperation.type === FileOperationType.Export) {
switch (fileOperation.format) {
case FileOperationFormat.HTMLZip:
await ExportHTMLZipTask.schedule({
await new ExportHTMLZipTask().schedule({
fileOperationId: event.modelId,
});
break;
case FileOperationFormat.MarkdownZip:
await ExportMarkdownZipTask.schedule({
await new ExportMarkdownZipTask().schedule({
fileOperationId: event.modelId,
});
break;
case FileOperationFormat.JSON:
await ExportJSONTask.schedule({
await new ExportJSONTask().schedule({
fileOperationId: event.modelId,
});
break;
@@ -62,25 +62,25 @@ export default class NotificationsProcessor extends BaseProcessor {
return;
}
await DocumentPublishedNotificationsTask.schedule(event);
await new DocumentPublishedNotificationsTask().schedule(event);
}
async documentAddUser(event: DocumentUserEvent) {
if (!event.data.isNew || event.userId === event.actorId) {
return;
}
await DocumentAddUserNotificationsTask.schedule(event);
await new DocumentAddUserNotificationsTask().schedule(event);
}
async documentAddGroup(event: DocumentGroupEvent) {
if (!event.data.isNew) {
return;
}
await DocumentAddGroupNotificationsTask.schedule(event);
await new DocumentAddGroupNotificationsTask().schedule(event);
}
async revisionCreated(event: RevisionEvent) {
await RevisionCreatedNotificationsTask.schedule(event);
await new RevisionCreatedNotificationsTask().schedule(event);
}
async collectionCreated(event: CollectionEvent) {
@@ -93,7 +93,7 @@ export default class NotificationsProcessor extends BaseProcessor {
return;
}
await CollectionCreatedNotificationsTask.schedule(event);
await new CollectionCreatedNotificationsTask().schedule(event);
}
async collectionAddUser(event: CollectionUserEvent) {
@@ -101,14 +101,14 @@ export default class NotificationsProcessor extends BaseProcessor {
return;
}
await CollectionAddUserNotificationsTask.schedule(event);
await new CollectionAddUserNotificationsTask().schedule(event);
}
async commentCreated(event: CommentEvent) {
await CommentCreatedNotificationsTask.schedule(event);
await new CommentCreatedNotificationsTask().schedule(event);
}
async commentUpdated(event: CommentEvent) {
await CommentUpdatedNotificationsTask.schedule(event);
await new CommentUpdatedNotificationsTask().schedule(event);
}
}
@@ -37,7 +37,7 @@ export default class RevisionsProcessor extends BaseProcessor {
return;
}
await DocumentUpdateTextTask.schedule(event);
await new DocumentUpdateTextTask().schedule(event);
const user = await User.findByPk(event.actorId, {
paranoid: false,
@@ -6,6 +6,6 @@ export default class UserDemotedProcessor extends BaseProcessor {
static applicableEvents: TEvent["name"][] = ["users.demote"];
async perform(event: UserEvent) {
await CleanupDemotedUserTask.schedule({ userId: event.userId });
await new CleanupDemotedUserTask().schedule({ userId: event.userId });
}
}
+3 -1
View File
@@ -325,7 +325,9 @@ export default abstract class APIImportTask<
([url, attachment]) => ({ attachmentId: attachment.id, url })
);
// publish task after attachments are persisted in DB.
const job = await UploadAttachmentsForImportTask.schedule(uploadItems);
const job = await new UploadAttachmentsForImportTask().schedule(
uploadItems
);
await job.finished();
} catch (err) {
// upload attachments failure is not critical enough to fail the whole import.
@@ -29,7 +29,7 @@ export default class CleanupDeletedTeamsTask extends BaseTask<Props> {
});
for (const team of teams) {
await CleanupDeletedTeamTask.schedule({
await new CleanupDeletedTeamTask().schedule({
teamId: team.id,
});
}
@@ -7,7 +7,7 @@ import BaseTask from "./BaseTask";
type Props = {
collectionId: string;
actorId: string;
ip: string;
ip: string | null;
};
export default class DetachDraftsFromCollectionTask extends BaseTask<Props> {
@@ -1,6 +1,6 @@
import { Op } from "sequelize";
import { GroupUser } from "@server/models";
import { DocumentGroupEvent } from "@server/types";
import { DocumentGroupEvent, DocumentUserEvent } from "@server/types";
import BaseTask, { TaskPriority } from "./BaseTask";
import DocumentAddUserNotificationsTask from "./DocumentAddUserNotificationsTask";
@@ -19,11 +19,12 @@ export default class DocumentAddGroupNotificationsTask extends BaseTask<Document
async (groupUsers) => {
await Promise.all(
groupUsers.map(async (groupUser) => {
await DocumentAddUserNotificationsTask.schedule({
await new DocumentAddUserNotificationsTask().schedule({
...event,
name: "documents.add_user",
modelId: event.data.membershipId,
userId: groupUser.userId,
});
} as DocumentUserEvent);
})
);
}
+1 -1
View File
@@ -12,7 +12,7 @@ type Props = {
sourceMetadata: Pick<Required<SourceMetadata>, "fileName" | "mimeType">;
publish?: boolean;
collectionId?: string;
parentDocumentId?: string;
parentDocumentId?: string | null;
ip: string;
key: string;
};
@@ -38,7 +38,7 @@ export default class UpdateTeamsAttachmentsSizeTask extends BaseTask<Props> {
const teamIds = rows.map((row) => row.teamId);
for (const teamId of teamIds) {
await UpdateTeamAttachmentsSizeTask.schedule({ teamId });
await new UpdateTeamAttachmentsSizeTask().schedule({ teamId });
}
}
);
+1 -1
View File
@@ -166,7 +166,7 @@ router.post(
)
);
const job = await UploadAttachmentFromUrlTask.schedule({
const job = await new UploadAttachmentFromUrlTask().schedule({
attachmentId: attachment.id,
url,
});
+1 -1
View File
@@ -135,7 +135,7 @@ router.post("auth.info", auth(), async (ctx: APIContext<T.AuthInfoReq>) => {
// If the user did not _just_ sign in then we need to check if they continue
// to have access to the workspace they are signed into.
if (user.lastSignedInAt && user.lastSignedInAt < subHours(new Date(), 1)) {
await ValidateSSOAccessTask.schedule({ userId: user.id });
await new ValidateSSOAccessTask().schedule({ userId: user.id });
}
ctx.body = {
+6 -3
View File
@@ -29,7 +29,8 @@ const cronHandler = async (ctx: APIContext<T.CronSchemaReq>) => {
for (const name in tasks) {
const TaskClass = tasks[name];
if (TaskClass.cron === period) {
await TaskClass.schedule({ limit });
// @ts-expect-error We won't instantiate an abstract class
await new TaskClass().schedule({ limit });
// Backwards compatibility for installations that have not set up
// cron jobs periods other than daily.
@@ -38,13 +39,15 @@ const cronHandler = async (ctx: APIContext<T.CronSchemaReq>) => {
!receivedPeriods.has(TaskSchedule.Minute) &&
(period === TaskSchedule.Hour || period === TaskSchedule.Day)
) {
await TaskClass.schedule({ limit });
// @ts-expect-error We won't instantiate an abstract class
await new TaskClass().schedule({ limit });
} else if (
TaskClass.cron === TaskSchedule.Hour &&
!receivedPeriods.has(TaskSchedule.Hour) &&
period === TaskSchedule.Day
) {
await TaskClass.schedule({ limit });
// @ts-expect-error We won't instantiate an abstract class
await new TaskClass().schedule({ limit });
}
}
+3 -2
View File
@@ -1539,7 +1539,7 @@ router.post(
acl,
});
const job = await DocumentImportTask.schedule({
const job = await new DocumentImportTask().schedule({
key,
sourceMetadata: {
fileName,
@@ -1549,6 +1549,7 @@ router.post(
collectionId,
parentDocumentId,
publish,
ip: ctx.request.ip,
});
const response: DocumentImportTaskResponse = await job.finished();
if ("error" in response) {
@@ -2062,7 +2063,7 @@ router.post(
});
if (documents.length) {
await EmptyTrashTask.schedule({
await new EmptyTrashTask().schedule({
documentIds: documents.map((doc) => doc.id),
});
}
+2 -1
View File
@@ -7,7 +7,8 @@ export default function init() {
for (const name in tasks) {
const TaskClass = tasks[name];
if (TaskClass.cron === schedule) {
await TaskClass.schedule({ limit: 10000 });
// @ts-expect-error We won't instantiate an abstract class
await new TaskClass().schedule({ limit: 10000 });
}
}
}