@sonamu-kit/tasks 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +15 -15
- package/dist/errors.d.ts +0 -8
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -21
- package/dist/errors.js.map +0 -1
- package/dist/practices/01-remote.d.ts +0 -2
- package/dist/practices/01-remote.d.ts.map +0 -1
- package/dist/practices/01-remote.js +0 -87
- package/dist/practices/01-remote.js.map +0 -1
- package/dist/practices/02-local.d.ts +0 -2
- package/dist/practices/02-local.d.ts.map +0 -1
- package/dist/practices/02-local.js +0 -84
- package/dist/practices/02-local.js.map +0 -1
- package/dist/practices/03-local-retry.d.ts +0 -2
- package/dist/practices/03-local-retry.d.ts.map +0 -1
- package/dist/practices/03-local-retry.js +0 -85
- package/dist/practices/03-local-retry.js.map +0 -1
- package/dist/practices/04-scheduler-dispose.d.ts +0 -2
- package/dist/practices/04-scheduler-dispose.d.ts.map +0 -1
- package/dist/practices/04-scheduler-dispose.js +0 -65
- package/dist/practices/04-scheduler-dispose.js.map +0 -1
- package/dist/practices/05-router.d.ts +0 -2
- package/dist/practices/05-router.d.ts.map +0 -1
- package/dist/practices/05-router.js +0 -80
- package/dist/practices/05-router.js.map +0 -1
- package/dist/scheduler.d.ts +0 -22
- package/dist/scheduler.d.ts.map +0 -1
- package/dist/scheduler.js +0 -117
- package/dist/scheduler.js.map +0 -1
- package/dist/tasks/index.d.ts +0 -4
- package/dist/tasks/index.d.ts.map +0 -1
- package/dist/tasks/index.js +0 -5
- package/dist/tasks/index.js.map +0 -1
- package/dist/tasks/local-task.d.ts +0 -6
- package/dist/tasks/local-task.d.ts.map +0 -1
- package/dist/tasks/local-task.js +0 -95
- package/dist/tasks/local-task.js.map +0 -1
- package/dist/tasks/remote-task.d.ts +0 -11
- package/dist/tasks/remote-task.d.ts.map +0 -1
- package/dist/tasks/remote-task.js +0 -213
- package/dist/tasks/remote-task.js.map +0 -1
- package/dist/tasks/shared.d.ts +0 -8
- package/dist/tasks/shared.d.ts.map +0 -1
- package/dist/tasks/shared.js +0 -41
- package/dist/tasks/shared.js.map +0 -1
- package/dist/types/config.d.ts +0 -44
- package/dist/types/config.d.ts.map +0 -1
- package/dist/types/config.js +0 -3
- package/dist/types/config.js.map +0 -1
- package/dist/types/context.d.ts +0 -18
- package/dist/types/context.d.ts.map +0 -1
- package/dist/types/context.js +0 -4
- package/dist/types/context.js.map +0 -1
- package/dist/types/events.d.ts +0 -43
- package/dist/types/events.d.ts.map +0 -1
- package/dist/types/events.js +0 -3
- package/dist/types/events.js.map +0 -1
- package/dist/types/index.d.ts +0 -6
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -3
- package/dist/types/index.js.map +0 -1
- package/dist/types/task-items.d.ts +0 -12
- package/dist/types/task-items.d.ts.map +0 -1
- package/dist/types/task-items.js +0 -3
- package/dist/types/task-items.js.map +0 -1
- package/dist/types/utils.d.ts +0 -4
- package/dist/types/utils.d.ts.map +0 -1
- package/dist/types/utils.js +0 -8
- package/dist/types/utils.js.map +0 -1
package/dist/scheduler.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import EventEmitter from "events";
|
|
2
|
-
import knex from "knex";
|
|
3
|
-
import { createTask } from "node-cron";
|
|
4
|
-
import { addRoute, createRouter } from "rou3";
|
|
5
|
-
import { v7 } from "uuid";
|
|
6
|
-
import { wrapRemoteTask, wrapLocalTask } from "./tasks/index.js";
|
|
7
|
-
import { resolve } from "./types/index.js";
|
|
8
|
-
// 태스크를 관리하는 Scheduler
|
|
9
|
-
export class SonamuScheduler {
|
|
10
|
-
#status = "stopped";
|
|
11
|
-
#event;
|
|
12
|
-
#knex;
|
|
13
|
-
#retry;
|
|
14
|
-
#router;
|
|
15
|
-
#tasks;
|
|
16
|
-
info;
|
|
17
|
-
constructor(knex, router, info, retry){
|
|
18
|
-
this.#event = new EventEmitter();
|
|
19
|
-
this.#knex = knex;
|
|
20
|
-
this.#retry = retry;
|
|
21
|
-
this.#router = router;
|
|
22
|
-
this.#tasks = [];
|
|
23
|
-
this.info = info;
|
|
24
|
-
}
|
|
25
|
-
// async disposable 처리를 위함
|
|
26
|
-
async [Symbol.asyncDispose]() {
|
|
27
|
-
return this.dispose();
|
|
28
|
-
}
|
|
29
|
-
addRoute(...routes) {
|
|
30
|
-
for (const route of routes){
|
|
31
|
-
addRoute(this.#router, "", route.path, {
|
|
32
|
-
...route,
|
|
33
|
-
info: this.info,
|
|
34
|
-
// route의 기본 설정 -> 글로벌 설정 -> 없을 경우 재시도는 안 함.
|
|
35
|
-
retry: {
|
|
36
|
-
delay: route.retry?.delay ?? this.#retry?.delay,
|
|
37
|
-
maxAttempts: route.retry?.maxAttempts ?? this.#retry?.maxAttempts ?? 1
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
addTask(...tasks) {
|
|
43
|
-
for (const task of tasks){
|
|
44
|
-
const onEvent = this.#emit.bind(this);
|
|
45
|
-
// remote냐 local이냐에 따라서 인자가 달라짐.
|
|
46
|
-
const func = task.type === "remote" ? wrapRemoteTask.bind(this, this.#router, this.info, onEvent, this.#knex) : wrapLocalTask.bind(this, this.#router, this.info, onEvent, {
|
|
47
|
-
id: v7(),
|
|
48
|
-
createdAt: new Date(),
|
|
49
|
-
updatedAt: new Date(),
|
|
50
|
-
status: "pending",
|
|
51
|
-
namespace: task.namespace,
|
|
52
|
-
attempt: 1,
|
|
53
|
-
payload: task.payload
|
|
54
|
-
});
|
|
55
|
-
const cronTask = createTask(task.expression, func, task.options);
|
|
56
|
-
this.#tasks.push(cronTask);
|
|
57
|
-
// Scheduler가 실행 상태일 때 task가 추가되면 Task도 같이 실행함
|
|
58
|
-
if (this.#status === "running") {
|
|
59
|
-
cronTask.start();
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
start() {
|
|
64
|
-
this.#status = "running";
|
|
65
|
-
for (const task of this.#tasks){
|
|
66
|
-
if (task.getStatus() === "stopped") {
|
|
67
|
-
task.start();
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
stop() {
|
|
72
|
-
this.#status = "stopped";
|
|
73
|
-
for (const task of this.#tasks){
|
|
74
|
-
if (task.getStatus() !== "stopped") {
|
|
75
|
-
task.stop();
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
async dispose() {
|
|
80
|
-
if (this.#status === "disposed") return;
|
|
81
|
-
this.#status = "disposed";
|
|
82
|
-
this.#event.removeAllListeners();
|
|
83
|
-
await this.#knex.destroy();
|
|
84
|
-
for (const task of this.#tasks){
|
|
85
|
-
task.stop();
|
|
86
|
-
await task.destroy();
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
// *를 넣으면 모든 이벤트에 대응함
|
|
90
|
-
on(name, fn) {
|
|
91
|
-
if (this.#status === "disposed") return;
|
|
92
|
-
this.#event.on(name, fn);
|
|
93
|
-
}
|
|
94
|
-
// *를 넣으면 모든 이벤트에 대응함
|
|
95
|
-
off(name, fn) {
|
|
96
|
-
if (this.#status === "disposed") return;
|
|
97
|
-
this.#event.off(name, fn);
|
|
98
|
-
}
|
|
99
|
-
// 내부 wrapLocalTask/wrapRemoteTask를 실행할 때 전달되는 event callback
|
|
100
|
-
#emit(evt) {
|
|
101
|
-
if (this.#status === "disposed") return;
|
|
102
|
-
this.#event.emit("*", evt);
|
|
103
|
-
this.#event.emit(evt.type, evt);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
export async function createScheduler(input) {
|
|
107
|
-
const config = await resolve(input);
|
|
108
|
-
const scheduler = new SonamuScheduler(knex(config.database), createRouter(), {
|
|
109
|
-
id: v7(),
|
|
110
|
-
name: config.name
|
|
111
|
-
}, config.retry);
|
|
112
|
-
scheduler.addRoute(...config.routes);
|
|
113
|
-
scheduler.addTask(...config.tasks);
|
|
114
|
-
return scheduler;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
//# sourceMappingURL=scheduler.js.map
|
package/dist/scheduler.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/scheduler.ts"],"sourcesContent":["import EventEmitter from \"events\";\nimport knex, { type Knex } from \"knex\";\nimport { createTask, type ScheduledTask } from \"node-cron\";\nimport { type RouterContext, addRoute, createRouter } from \"rou3\";\nimport { v7 } from \"uuid\";\nimport { wrapRemoteTask, wrapLocalTask } from \"./tasks\";\nimport {\n resolve,\n type EventType,\n type LocalTaskConfig,\n type SchedulerInfo,\n type OnEventFunction,\n type RemoteTaskConfig,\n type Resolvable,\n type RetryConfig,\n type TaskEvent,\n type SchedulerConfig,\n type TaskRouterContext,\n} from \"./types\";\n\n// 태스크를 관리하는 Scheduler\nexport class SonamuScheduler {\n #status: \"running\" | \"stopped\" | \"disposed\" = \"stopped\";\n\n readonly #event: EventEmitter;\n readonly #knex: Knex;\n readonly #retry?: RetryConfig;\n readonly #router: RouterContext<TaskRouterContext & { info: SchedulerInfo }>;\n readonly #tasks: ScheduledTask[];\n readonly info: SchedulerInfo;\n\n constructor(\n knex: Knex,\n router: RouterContext<TaskRouterContext & { info: SchedulerInfo }>,\n info: SchedulerInfo,\n retry?: RetryConfig,\n ) {\n this.#event = new EventEmitter();\n this.#knex = knex;\n this.#retry = retry;\n this.#router = router;\n this.#tasks = [];\n this.info = info;\n }\n\n // async disposable 처리를 위함\n async [Symbol.asyncDispose]() {\n return this.dispose();\n }\n\n addRoute(...routes: (Omit<TaskRouterContext, \"retry\"> & { retry?: RetryConfig })[]) {\n for (const route of routes) {\n addRoute(this.#router, \"\", route.path, {\n ...route,\n info: this.info,\n // route의 기본 설정 -> 글로벌 설정 -> 없을 경우 재시도는 안 함.\n retry: {\n delay: route.retry?.delay ?? this.#retry?.delay,\n maxAttempts: route.retry?.maxAttempts ?? this.#retry?.maxAttempts ?? 1,\n },\n });\n }\n }\n\n addTask(...tasks: (RemoteTaskConfig | LocalTaskConfig)[]) {\n for (const task of tasks) {\n const onEvent = this.#emit.bind(this);\n // remote냐 local이냐에 따라서 인자가 달라짐.\n const func =\n task.type === \"remote\"\n ? wrapRemoteTask.bind(this, this.#router, this.info, onEvent, this.#knex)\n : wrapLocalTask.bind(this, this.#router, this.info, onEvent, {\n id: v7(),\n createdAt: new Date(),\n updatedAt: new Date(),\n status: \"pending\",\n namespace: task.namespace,\n attempt: 1,\n payload: task.payload,\n });\n\n const cronTask = createTask(task.expression, func, task.options);\n this.#tasks.push(cronTask);\n\n // Scheduler가 실행 상태일 때 task가 추가되면 Task도 같이 실행함\n if (this.#status === \"running\") {\n cronTask.start();\n }\n }\n }\n\n start() {\n this.#status = \"running\";\n for (const task of this.#tasks) {\n if (task.getStatus() === \"stopped\") {\n task.start();\n }\n }\n }\n\n stop() {\n this.#status = \"stopped\";\n for (const task of this.#tasks) {\n if (task.getStatus() !== \"stopped\") {\n task.stop();\n }\n }\n }\n\n async dispose() {\n if (this.#status === \"disposed\") return;\n\n this.#status = \"disposed\";\n this.#event.removeAllListeners();\n await this.#knex.destroy();\n\n for (const task of this.#tasks) {\n task.stop();\n await task.destroy();\n }\n }\n\n // *를 넣으면 모든 이벤트에 대응함\n on(name: EventType | \"*\", fn: OnEventFunction) {\n if (this.#status === \"disposed\") return;\n this.#event.on(name, fn);\n }\n\n // *를 넣으면 모든 이벤트에 대응함\n off(name: EventType | \"*\", fn: OnEventFunction) {\n if (this.#status === \"disposed\") return;\n this.#event.off(name, fn);\n }\n\n // 내부 wrapLocalTask/wrapRemoteTask를 실행할 때 전달되는 event callback\n #emit(evt: TaskEvent) {\n if (this.#status === \"disposed\") return;\n this.#event.emit(\"*\", evt);\n this.#event.emit(evt.type, evt);\n }\n}\n\nexport async function createScheduler(\n input: Resolvable<SchedulerConfig>,\n): Promise<SonamuScheduler> {\n const config = await resolve(input);\n const scheduler = new SonamuScheduler(\n knex(config.database),\n createRouter(),\n { id: v7(), name: config.name },\n config.retry,\n );\n\n scheduler.addRoute(...config.routes);\n scheduler.addTask(...config.tasks);\n return scheduler;\n}\n"],"names":["EventEmitter","knex","createTask","addRoute","createRouter","v7","wrapRemoteTask","wrapLocalTask","resolve","SonamuScheduler","info","router","retry","Symbol","asyncDispose","dispose","routes","route","path","delay","maxAttempts","addTask","tasks","task","onEvent","bind","func","type","id","createdAt","Date","updatedAt","status","namespace","attempt","payload","cronTask","expression","options","push","start","getStatus","stop","removeAllListeners","destroy","on","name","fn","off","evt","emit","createScheduler","input","config","scheduler","database"],"mappings":"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"}
|
package/dist/tasks/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tasks/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC"}
|
package/dist/tasks/index.js
DELETED
package/dist/tasks/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/tasks/index.ts"],"sourcesContent":["export * from \"./local-task\";\nexport * from \"./remote-task\";\nexport * from \"./shared\";\n"],"names":[],"mappings":"AAAA,cAAc,kBAAe;AAC7B,cAAc,mBAAgB;AAC9B,cAAc,cAAW"}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type RouterContext } from "rou3";
|
|
2
|
-
import type { SchedulerInfo, TaskEvent, TaskItem, TaskRouterContext } from "../types";
|
|
3
|
-
export declare function wrapLocalTask(router: RouterContext<TaskRouterContext & {
|
|
4
|
-
info: SchedulerInfo;
|
|
5
|
-
}>, info: SchedulerInfo, onEvent: (data: TaskEvent) => void, item: TaskItem): Promise<void>;
|
|
6
|
-
//# sourceMappingURL=local-task.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"local-task.d.ts","sourceRoot":"","sources":["../../src/tasks/local-task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,aAAa,EAAE,MAAM,MAAM,CAAC;AAErD,OAAO,KAAK,EACV,aAAa,EAGb,SAAS,EACT,QAAQ,EACR,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAoClB,wBAAsB,aAAa,CACjC,MAAM,EAAE,aAAa,CAAC,iBAAiB,GAAG;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC,EAClE,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,EAClC,IAAI,EAAE,QAAQ,iBA0Ef"}
|
package/dist/tasks/local-task.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { findRoute } from "rou3";
|
|
2
|
-
import { isSonamuTaskError } from "../errors.js";
|
|
3
|
-
import { routedAction } from "./shared.js";
|
|
4
|
-
// Local 실행일 떄 Retry 설정에서 duration을 체크하는 법.
|
|
5
|
-
function getDuration(attempt, delay) {
|
|
6
|
-
// duration이 함수일 경우, 시도 횟수를 넣어서 계산
|
|
7
|
-
if (delay instanceof Function) {
|
|
8
|
-
return delay(attempt);
|
|
9
|
-
}
|
|
10
|
-
return delay ?? {
|
|
11
|
-
minutes: 1
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
// date를 기점으로 duration을 계산해서 ms로 변환.
|
|
15
|
-
function calculateToMs(duration) {
|
|
16
|
-
const MS_PER_SECOND = 1000;
|
|
17
|
-
const MS_PER_MINUTE = 60 * MS_PER_SECOND;
|
|
18
|
-
const MS_PER_HOUR = 60 * MS_PER_MINUTE;
|
|
19
|
-
const MS_PER_DAY = 24 * MS_PER_HOUR;
|
|
20
|
-
const MS_PER_WEEK = 7 * MS_PER_DAY;
|
|
21
|
-
const MS_PER_MONTH = 30 * MS_PER_DAY;
|
|
22
|
-
const MS_PER_YEAR = 365 * MS_PER_DAY;
|
|
23
|
-
return (duration.years ?? 0) * MS_PER_YEAR + (duration.months ?? 0) * MS_PER_MONTH + (duration.weeks ?? 0) * MS_PER_WEEK + (duration.days ?? 0) * MS_PER_DAY + (duration.hours ?? 0) * MS_PER_HOUR + (duration.minutes ?? 0) * MS_PER_MINUTE + (duration.seconds ?? 0) * MS_PER_SECOND;
|
|
24
|
-
}
|
|
25
|
-
// Scheduler에서 Local Task가 돌아갈 때 실행되는 부분
|
|
26
|
-
export async function wrapLocalTask(router, info, onEvent, item) {
|
|
27
|
-
// Router에서 Route를 찾아서
|
|
28
|
-
const matched = findRoute(router, "", item.namespace);
|
|
29
|
-
if (!matched) {
|
|
30
|
-
onEvent({
|
|
31
|
-
type: "process:error",
|
|
32
|
-
task: item,
|
|
33
|
-
timestamp: new Date(),
|
|
34
|
-
info: info,
|
|
35
|
-
reason: "no_route"
|
|
36
|
-
});
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
// 재시도 처리를 함
|
|
40
|
-
while(item.attempt <= matched.data.retry.maxAttempts){
|
|
41
|
-
try {
|
|
42
|
-
await routedAction(matched, item);
|
|
43
|
-
await (async ()=>{
|
|
44
|
-
const event = {
|
|
45
|
-
type: "process:complete",
|
|
46
|
-
task: item,
|
|
47
|
-
timestamp: new Date(),
|
|
48
|
-
info: matched.data.info
|
|
49
|
-
};
|
|
50
|
-
onEvent(event);
|
|
51
|
-
})();
|
|
52
|
-
return;
|
|
53
|
-
} catch (err) {
|
|
54
|
-
let evt;
|
|
55
|
-
if (isSonamuTaskError(err)) {
|
|
56
|
-
evt = {
|
|
57
|
-
type: "process:error",
|
|
58
|
-
task: item,
|
|
59
|
-
timestamp: new Date(),
|
|
60
|
-
info: matched.data.info,
|
|
61
|
-
reason: err.type,
|
|
62
|
-
error: err.cause ?? err
|
|
63
|
-
};
|
|
64
|
-
} else if (err instanceof Error) {
|
|
65
|
-
evt = {
|
|
66
|
-
type: "process:error",
|
|
67
|
-
task: item,
|
|
68
|
-
timestamp: new Date(),
|
|
69
|
-
info: matched.data.info,
|
|
70
|
-
reason: "exception",
|
|
71
|
-
error: err
|
|
72
|
-
};
|
|
73
|
-
} else {
|
|
74
|
-
evt = {
|
|
75
|
-
type: "process:error",
|
|
76
|
-
task: item,
|
|
77
|
-
timestamp: new Date(),
|
|
78
|
-
info: matched.data.info,
|
|
79
|
-
reason: "exception",
|
|
80
|
-
error: new Error(`Unknown Error: ${err}`)
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
onEvent(evt);
|
|
84
|
-
if (item.attempt < matched.data.retry.maxAttempts) {
|
|
85
|
-
await new Promise((resolve)=>setTimeout(resolve, calculateToMs(getDuration(item.attempt, matched.data.retry.delay))));
|
|
86
|
-
}
|
|
87
|
-
item = {
|
|
88
|
-
...item,
|
|
89
|
-
attempt: item.attempt + 1
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
//# sourceMappingURL=local-task.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/tasks/local-task.ts"],"sourcesContent":["import { findRoute, type RouterContext } from \"rou3\";\nimport { isSonamuTaskError } from \"../errors\";\nimport type {\n SchedulerInfo,\n RetryConfig,\n RoutedTaskEvent,\n TaskEvent,\n TaskItem,\n TaskRouterContext,\n} from \"../types\";\nimport { routedAction } from \"./shared\";\nimport type { Duration } from \"date-fns\";\n\n// Local 실행일 떄 Retry 설정에서 duration을 체크하는 법.\nfunction getDuration(attempt: number, delay: RetryConfig[\"delay\"]): Duration {\n // duration이 함수일 경우, 시도 횟수를 넣어서 계산\n if (delay instanceof Function) {\n return delay(attempt);\n }\n\n return delay ?? { minutes: 1 };\n}\n\n// date를 기점으로 duration을 계산해서 ms로 변환.\nfunction calculateToMs(duration: Duration): number {\n const MS_PER_SECOND = 1000;\n const MS_PER_MINUTE = 60 * MS_PER_SECOND;\n const MS_PER_HOUR = 60 * MS_PER_MINUTE;\n const MS_PER_DAY = 24 * MS_PER_HOUR;\n const MS_PER_WEEK = 7 * MS_PER_DAY;\n const MS_PER_MONTH = 30 * MS_PER_DAY;\n const MS_PER_YEAR = 365 * MS_PER_DAY;\n\n return (\n (duration.years ?? 0) * MS_PER_YEAR +\n (duration.months ?? 0) * MS_PER_MONTH +\n (duration.weeks ?? 0) * MS_PER_WEEK +\n (duration.days ?? 0) * MS_PER_DAY +\n (duration.hours ?? 0) * MS_PER_HOUR +\n (duration.minutes ?? 0) * MS_PER_MINUTE +\n (duration.seconds ?? 0) * MS_PER_SECOND\n );\n}\n\n// Scheduler에서 Local Task가 돌아갈 때 실행되는 부분\nexport async function wrapLocalTask(\n router: RouterContext<TaskRouterContext & { info: SchedulerInfo }>,\n info: SchedulerInfo,\n onEvent: (data: TaskEvent) => void,\n item: TaskItem,\n) {\n // Router에서 Route를 찾아서\n const matched = findRoute(router, \"\", item.namespace);\n if (!matched) {\n onEvent({\n type: \"process:error\",\n task: item,\n timestamp: new Date(),\n info: info,\n reason: \"no_route\",\n });\n return;\n }\n\n // 재시도 처리를 함\n while (item.attempt <= matched.data.retry.maxAttempts) {\n try {\n await routedAction(matched, item);\n await (async () => {\n const event: RoutedTaskEvent = {\n type: \"process:complete\",\n task: item,\n timestamp: new Date(),\n info: matched.data.info,\n };\n\n onEvent(event);\n })();\n return;\n } catch (err) {\n let evt: RoutedTaskEvent;\n if (isSonamuTaskError(err)) {\n evt = {\n type: \"process:error\",\n task: item,\n timestamp: new Date(),\n info: matched.data.info,\n reason: err.type,\n error: err.cause ?? err,\n };\n } else if (err instanceof Error) {\n evt = {\n type: \"process:error\",\n task: item,\n timestamp: new Date(),\n info: matched.data.info,\n reason: \"exception\",\n error: err,\n };\n } else {\n evt = {\n type: \"process:error\",\n task: item,\n timestamp: new Date(),\n info: matched.data.info,\n reason: \"exception\",\n error: new Error(`Unknown Error: ${err}`),\n };\n }\n onEvent(evt);\n\n if (item.attempt < matched.data.retry.maxAttempts) {\n await new Promise((resolve) =>\n setTimeout(resolve, calculateToMs(getDuration(item.attempt, matched.data.retry.delay))),\n );\n }\n\n item = {\n ...item,\n attempt: item.attempt + 1,\n };\n }\n }\n}\n"],"names":["findRoute","isSonamuTaskError","routedAction","getDuration","attempt","delay","Function","minutes","calculateToMs","duration","MS_PER_SECOND","MS_PER_MINUTE","MS_PER_HOUR","MS_PER_DAY","MS_PER_WEEK","MS_PER_MONTH","MS_PER_YEAR","years","months","weeks","days","hours","seconds","wrapLocalTask","router","info","onEvent","item","matched","namespace","type","task","timestamp","Date","reason","data","retry","maxAttempts","event","err","evt","error","cause","Error","Promise","resolve","setTimeout"],"mappings":"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"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { Knex } from "knex";
|
|
2
|
-
import type { SchedulerInfo, UnroutedTaskEvent, RoutedTaskEvent, TaskRouterContext, TaskEvent } from "../types";
|
|
3
|
-
import { type RouterContext } from "rou3";
|
|
4
|
-
export declare function saveUnroutedTaskEvent(knex: Knex, data: UnroutedTaskEvent): Promise<number[]>;
|
|
5
|
-
export declare function saveRoutedTaskEvent<T extends RoutedTaskEvent>(knex: Knex, router: RouterContext<TaskRouterContext & {
|
|
6
|
-
info: SchedulerInfo;
|
|
7
|
-
}>, data: T): Promise<void>;
|
|
8
|
-
export declare function wrapRemoteTask(router: RouterContext<TaskRouterContext & {
|
|
9
|
-
info: SchedulerInfo;
|
|
10
|
-
}>, info: SchedulerInfo, onEvent: (data: TaskEvent) => void, knex: Knex): Promise<void>;
|
|
11
|
-
//# sourceMappingURL=remote-task.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"remote-task.d.ts","sourceRoot":"","sources":["../../src/tasks/remote-task.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,KAAK,EACV,aAAa,EAEb,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,SAAS,EACV,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,KAAK,aAAa,EAAa,MAAM,MAAM,CAAC;AAKrD,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,iBAAiB,qBAoC9E;AAGD,wBAAsB,mBAAmB,CAAC,CAAC,SAAS,eAAe,EACjE,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,aAAa,CAAC,iBAAiB,GAAG;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC,EAClE,IAAI,EAAE,CAAC,iBA0GR;AAID,wBAAsB,cAAc,CAClC,MAAM,EAAE,aAAa,CAAC,iBAAiB,GAAG;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC,EAClE,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,EAClC,IAAI,EAAE,IAAI,iBAsHX"}
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import { findRoute } from "rou3";
|
|
2
|
-
import { isSonamuTaskError } from "../errors.js";
|
|
3
|
-
import { routedAction } from "./shared.js";
|
|
4
|
-
// start, stop, fetch 이벤트는 router를 잡기 전에 일어나서 별도로 분리
|
|
5
|
-
export async function saveUnroutedTaskEvent(knex, data) {
|
|
6
|
-
switch(data.type){
|
|
7
|
-
case "start":
|
|
8
|
-
return knex.insert({
|
|
9
|
-
event_type: data.type,
|
|
10
|
-
info_id: knex.fn.uuidToBin(data.info.id),
|
|
11
|
-
info_name: data.info.name,
|
|
12
|
-
timestamp: data.timestamp
|
|
13
|
-
}).into("sonamu_task_events");
|
|
14
|
-
case "stop":
|
|
15
|
-
return knex.insert({
|
|
16
|
-
event_type: data.type,
|
|
17
|
-
info_id: knex.fn.uuidToBin(data.info.id),
|
|
18
|
-
info_name: data.info.name,
|
|
19
|
-
timestamp: data.timestamp,
|
|
20
|
-
reason: data.reason,
|
|
21
|
-
error_message: data.error?.message,
|
|
22
|
-
error_stack: data.error?.stack
|
|
23
|
-
}).into("sonamu_task_events");
|
|
24
|
-
case "fetch":
|
|
25
|
-
return knex.insert({
|
|
26
|
-
event_type: data.type,
|
|
27
|
-
info_id: knex.fn.uuidToBin(data.info.id),
|
|
28
|
-
info_name: data.info.name,
|
|
29
|
-
timestamp: data.timestamp
|
|
30
|
-
}).into("sonamu_task_events");
|
|
31
|
-
default:
|
|
32
|
-
throw new Error(`Unknown task event type: ${data.type}`);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
// router에서 매칭 후 생긴 이벤트를 처리
|
|
36
|
-
export async function saveRoutedTaskEvent(knex, router, data) {
|
|
37
|
-
const queries = [];
|
|
38
|
-
const matched = findRoute(router, "", data.task.namespace);
|
|
39
|
-
switch(data.type){
|
|
40
|
-
case "process:start":
|
|
41
|
-
queries.push(knex.insert({
|
|
42
|
-
event_type: data.type,
|
|
43
|
-
info_id: knex.fn.uuidToBin(data.info.id),
|
|
44
|
-
info_name: data.info.name,
|
|
45
|
-
timestamp: data.timestamp,
|
|
46
|
-
task_item_id: knex.fn.uuidToBin(data.task.id),
|
|
47
|
-
attempt: data.task.attempt
|
|
48
|
-
}).into("sonamu_task_events"));
|
|
49
|
-
break;
|
|
50
|
-
case "process:complete":
|
|
51
|
-
// sonamu_task_items의 TaskItem을 sonamu_archived_task_items로 이동
|
|
52
|
-
queries.push(knex.insert({
|
|
53
|
-
event_type: data.type,
|
|
54
|
-
info_id: knex.fn.uuidToBin(data.info.id),
|
|
55
|
-
info_name: data.info.name,
|
|
56
|
-
timestamp: data.timestamp,
|
|
57
|
-
task_item_id: knex.fn.uuidToBin(data.task.id),
|
|
58
|
-
attempt: data.task.attempt
|
|
59
|
-
}).into("sonamu_task_events"));
|
|
60
|
-
queries.push(knex("sonamu_task_items").where("id", knex.fn.uuidToBin(data.task.id)).delete());
|
|
61
|
-
queries.push(knex.insert({
|
|
62
|
-
id: knex.fn.uuidToBin(data.task.id),
|
|
63
|
-
created_at: data.task.createdAt,
|
|
64
|
-
completed_at: data.timestamp,
|
|
65
|
-
namespace: data.task.namespace,
|
|
66
|
-
payload: data.task.payload,
|
|
67
|
-
attempt: data.task.attempt,
|
|
68
|
-
status: "completed"
|
|
69
|
-
}).into("sonamu_archived_task_items"));
|
|
70
|
-
break;
|
|
71
|
-
case "process:error":
|
|
72
|
-
queries.push(knex.insert({
|
|
73
|
-
event_type: data.type,
|
|
74
|
-
info_id: knex.fn.uuidToBin(data.info.id),
|
|
75
|
-
info_name: data.info.name,
|
|
76
|
-
timestamp: data.timestamp,
|
|
77
|
-
task_item_id: knex.fn.uuidToBin(data.task.id),
|
|
78
|
-
attempt: data.task.attempt,
|
|
79
|
-
reason: data.reason,
|
|
80
|
-
error_message: data.error?.message,
|
|
81
|
-
error_stack: data.error?.stack
|
|
82
|
-
}).into("sonamu_task_events"));
|
|
83
|
-
if (data.task.attempt >= (matched?.data.retry.maxAttempts ?? 1)) {
|
|
84
|
-
// 최대 실행 횟수를 넘겼을 경우, 에러로 sonamu_archived_task_items로 옮김
|
|
85
|
-
queries.push(knex("sonamu_task_items").where("id", knex.fn.uuidToBin(data.task.id)).delete());
|
|
86
|
-
queries.push(knex.insert({
|
|
87
|
-
id: knex.fn.uuidToBin(data.task.id),
|
|
88
|
-
created_at: data.task.createdAt,
|
|
89
|
-
completed_at: data.timestamp,
|
|
90
|
-
namespace: data.task.namespace,
|
|
91
|
-
payload: data.task.payload,
|
|
92
|
-
attempt: data.task.attempt,
|
|
93
|
-
status: "error"
|
|
94
|
-
}).into("sonamu_archived_task_items"));
|
|
95
|
-
} else {
|
|
96
|
-
// 재시도 횟수 증가 및 상태 업데이트
|
|
97
|
-
queries.push(knex("sonamu_task_items").where("id", knex.fn.uuidToBin(data.task.id)).update({
|
|
98
|
-
status: "pending",
|
|
99
|
-
attempt: data.task.attempt + 1,
|
|
100
|
-
updated_at: data.timestamp
|
|
101
|
-
}));
|
|
102
|
-
}
|
|
103
|
-
break;
|
|
104
|
-
default:
|
|
105
|
-
throw new Error(`Unknown task type: ${data}`);
|
|
106
|
-
}
|
|
107
|
-
await Promise.all(queries);
|
|
108
|
-
}
|
|
109
|
-
// Scheduler에서 Remote Task가 돌아갈 때 실행되는 부분
|
|
110
|
-
// TODO: Retry를 지금은 서버에서 처리하기 떄문에 delay가 적용되지 않음.
|
|
111
|
-
export async function wrapRemoteTask(router, info, onEvent, knex) {
|
|
112
|
-
const trx = await knex.transaction();
|
|
113
|
-
await (async ()=>{
|
|
114
|
-
const event = {
|
|
115
|
-
type: "fetch",
|
|
116
|
-
info: info,
|
|
117
|
-
timestamp: new Date()
|
|
118
|
-
};
|
|
119
|
-
onEvent(event);
|
|
120
|
-
await saveUnroutedTaskEvent(trx, event);
|
|
121
|
-
})();
|
|
122
|
-
// NOTE: 대기 처리를 Queue를 별도로 분리한다면 where status = "pending_for_retry"를 추가하면 됨.
|
|
123
|
-
const rawTask = await trx.select("id", "created_at", "updated_at", "namespace", "status", "attempt", "payload").from("sonamu_task_items").forUpdate().skipLocked().limit(1).first();
|
|
124
|
-
if (!rawTask) {
|
|
125
|
-
await trx.rollback();
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
const item = {
|
|
129
|
-
id: knex.fn.binToUuid(rawTask.id),
|
|
130
|
-
createdAt: rawTask.created_at,
|
|
131
|
-
updatedAt: rawTask.updated_at,
|
|
132
|
-
status: rawTask.status,
|
|
133
|
-
namespace: rawTask.namespace,
|
|
134
|
-
attempt: rawTask.attempt,
|
|
135
|
-
payload: rawTask.payload
|
|
136
|
-
};
|
|
137
|
-
await (async ()=>{
|
|
138
|
-
const event = {
|
|
139
|
-
type: "process:start",
|
|
140
|
-
task: item,
|
|
141
|
-
timestamp: new Date(),
|
|
142
|
-
info: info
|
|
143
|
-
};
|
|
144
|
-
onEvent(event);
|
|
145
|
-
await saveRoutedTaskEvent(trx, router, event);
|
|
146
|
-
})();
|
|
147
|
-
// Router에서 Route를 찾음
|
|
148
|
-
const matched = findRoute(router, "", item.namespace);
|
|
149
|
-
if (!matched) {
|
|
150
|
-
await (async ()=>{
|
|
151
|
-
const event = {
|
|
152
|
-
type: "process:error",
|
|
153
|
-
task: item,
|
|
154
|
-
timestamp: new Date(),
|
|
155
|
-
info: info,
|
|
156
|
-
reason: "no_route"
|
|
157
|
-
};
|
|
158
|
-
onEvent(event);
|
|
159
|
-
await saveRoutedTaskEvent(trx, router, event);
|
|
160
|
-
})();
|
|
161
|
-
await trx.commit();
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
try {
|
|
165
|
-
await routedAction(matched, item);
|
|
166
|
-
await (async ()=>{
|
|
167
|
-
const event = {
|
|
168
|
-
type: "process:complete",
|
|
169
|
-
task: item,
|
|
170
|
-
timestamp: new Date(),
|
|
171
|
-
info: matched.data.info
|
|
172
|
-
};
|
|
173
|
-
onEvent(event);
|
|
174
|
-
await saveRoutedTaskEvent(trx, router, event);
|
|
175
|
-
})();
|
|
176
|
-
} catch (err) {
|
|
177
|
-
let evt;
|
|
178
|
-
if (isSonamuTaskError(err)) {
|
|
179
|
-
evt = {
|
|
180
|
-
type: "process:error",
|
|
181
|
-
task: item,
|
|
182
|
-
timestamp: new Date(),
|
|
183
|
-
info: matched.data.info,
|
|
184
|
-
reason: err.type,
|
|
185
|
-
error: err.cause ?? err
|
|
186
|
-
};
|
|
187
|
-
} else if (err instanceof Error) {
|
|
188
|
-
evt = {
|
|
189
|
-
type: "process:error",
|
|
190
|
-
task: item,
|
|
191
|
-
timestamp: new Date(),
|
|
192
|
-
info: matched.data.info,
|
|
193
|
-
reason: "exception",
|
|
194
|
-
error: err
|
|
195
|
-
};
|
|
196
|
-
} else {
|
|
197
|
-
evt = {
|
|
198
|
-
type: "process:error",
|
|
199
|
-
task: item,
|
|
200
|
-
timestamp: new Date(),
|
|
201
|
-
info: matched.data.info,
|
|
202
|
-
reason: "exception",
|
|
203
|
-
error: new Error(`Unknown Error: ${err}`)
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
onEvent(evt);
|
|
207
|
-
await saveRoutedTaskEvent(trx, router, evt);
|
|
208
|
-
} finally{
|
|
209
|
-
await trx.commit();
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
//# sourceMappingURL=remote-task.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/tasks/remote-task.ts"],"sourcesContent":["import type { Knex } from \"knex\";\nimport type {\n SchedulerInfo,\n TaskItem,\n UnroutedTaskEvent,\n RoutedTaskEvent,\n TaskRouterContext,\n TaskEvent,\n} from \"../types\";\nimport { type RouterContext, findRoute } from \"rou3\";\nimport { isSonamuTaskError } from \"../errors\";\nimport { routedAction } from \"./shared\";\n\n// start, stop, fetch 이벤트는 router를 잡기 전에 일어나서 별도로 분리\nexport async function saveUnroutedTaskEvent(knex: Knex, data: UnroutedTaskEvent) {\n switch (data.type) {\n case \"start\":\n return knex\n .insert({\n event_type: data.type,\n info_id: knex.fn.uuidToBin(data.info.id),\n info_name: data.info.name,\n timestamp: data.timestamp,\n })\n .into(\"sonamu_task_events\");\n case \"stop\":\n return knex\n .insert({\n event_type: data.type,\n info_id: knex.fn.uuidToBin(data.info.id),\n info_name: data.info.name,\n timestamp: data.timestamp,\n reason: data.reason,\n error_message: data.error?.message,\n error_stack: data.error?.stack,\n })\n .into(\"sonamu_task_events\");\n case \"fetch\":\n return knex\n .insert({\n event_type: data.type,\n info_id: knex.fn.uuidToBin(data.info.id),\n info_name: data.info.name,\n timestamp: data.timestamp,\n })\n .into(\"sonamu_task_events\");\n\n default:\n throw new Error(`Unknown task event type: ${(data as any).type}`);\n }\n}\n\n// router에서 매칭 후 생긴 이벤트를 처리\nexport async function saveRoutedTaskEvent<T extends RoutedTaskEvent>(\n knex: Knex,\n router: RouterContext<TaskRouterContext & { info: SchedulerInfo }>,\n data: T,\n) {\n const queries: Knex.QueryBuilder[] = [];\n const matched = findRoute(router, \"\", data.task.namespace);\n\n switch (data.type) {\n case \"process:start\":\n queries.push(\n knex\n .insert({\n event_type: data.type,\n info_id: knex.fn.uuidToBin(data.info.id),\n info_name: data.info.name,\n timestamp: data.timestamp,\n task_item_id: knex.fn.uuidToBin(data.task.id),\n attempt: data.task.attempt,\n })\n .into(\"sonamu_task_events\"),\n );\n break;\n\n case \"process:complete\":\n // sonamu_task_items의 TaskItem을 sonamu_archived_task_items로 이동\n queries.push(\n knex\n .insert({\n event_type: data.type,\n info_id: knex.fn.uuidToBin(data.info.id),\n info_name: data.info.name,\n timestamp: data.timestamp,\n task_item_id: knex.fn.uuidToBin(data.task.id),\n attempt: data.task.attempt,\n })\n .into(\"sonamu_task_events\"),\n );\n queries.push(knex(\"sonamu_task_items\").where(\"id\", knex.fn.uuidToBin(data.task.id)).delete());\n queries.push(\n knex\n .insert({\n id: knex.fn.uuidToBin(data.task.id),\n created_at: data.task.createdAt,\n completed_at: data.timestamp,\n namespace: data.task.namespace,\n payload: data.task.payload,\n attempt: data.task.attempt,\n status: \"completed\",\n })\n .into(\"sonamu_archived_task_items\"),\n );\n break;\n\n case \"process:error\":\n queries.push(\n knex\n .insert({\n event_type: data.type,\n info_id: knex.fn.uuidToBin(data.info.id),\n info_name: data.info.name,\n timestamp: data.timestamp,\n task_item_id: knex.fn.uuidToBin(data.task.id),\n attempt: data.task.attempt,\n reason: data.reason,\n error_message: data.error?.message,\n error_stack: data.error?.stack,\n })\n .into(\"sonamu_task_events\"),\n );\n\n if (data.task.attempt >= (matched?.data.retry.maxAttempts ?? 1)) {\n // 최대 실행 횟수를 넘겼을 경우, 에러로 sonamu_archived_task_items로 옮김\n queries.push(\n knex(\"sonamu_task_items\").where(\"id\", knex.fn.uuidToBin(data.task.id)).delete(),\n );\n\n queries.push(\n knex\n .insert({\n id: knex.fn.uuidToBin(data.task.id),\n created_at: data.task.createdAt,\n completed_at: data.timestamp,\n namespace: data.task.namespace,\n payload: data.task.payload,\n attempt: data.task.attempt,\n status: \"error\",\n })\n .into(\"sonamu_archived_task_items\"),\n );\n } else {\n // 재시도 횟수 증가 및 상태 업데이트\n queries.push(\n knex(\"sonamu_task_items\")\n .where(\"id\", knex.fn.uuidToBin(data.task.id))\n .update({\n status: \"pending\",\n attempt: data.task.attempt + 1,\n updated_at: data.timestamp,\n }),\n );\n }\n break;\n\n default:\n throw new Error(`Unknown task type: ${data}`);\n }\n\n await Promise.all(queries);\n}\n\n// Scheduler에서 Remote Task가 돌아갈 때 실행되는 부분\n// TODO: Retry를 지금은 서버에서 처리하기 떄문에 delay가 적용되지 않음.\nexport async function wrapRemoteTask(\n router: RouterContext<TaskRouterContext & { info: SchedulerInfo }>,\n info: SchedulerInfo,\n onEvent: (data: TaskEvent) => void,\n knex: Knex,\n) {\n const trx = await knex.transaction();\n await (async () => {\n const event: UnroutedTaskEvent = {\n type: \"fetch\",\n info: info,\n timestamp: new Date(),\n };\n\n onEvent(event);\n await saveUnroutedTaskEvent(trx, event);\n })();\n\n // NOTE: 대기 처리를 Queue를 별도로 분리한다면 where status = \"pending_for_retry\"를 추가하면 됨.\n const rawTask = await trx\n .select(\"id\", \"created_at\", \"updated_at\", \"namespace\", \"status\", \"attempt\", \"payload\")\n .from(\"sonamu_task_items\")\n .forUpdate()\n .skipLocked()\n .limit(1)\n .first();\n\n if (!rawTask) {\n await trx.rollback();\n return;\n }\n\n const item: TaskItem = {\n id: knex.fn.binToUuid(rawTask.id),\n createdAt: rawTask.created_at,\n updatedAt: rawTask.updated_at,\n status: rawTask.status,\n namespace: rawTask.namespace,\n attempt: rawTask.attempt,\n payload: rawTask.payload,\n };\n\n await (async () => {\n const event: RoutedTaskEvent = {\n type: \"process:start\",\n task: item,\n timestamp: new Date(),\n info: info,\n };\n\n onEvent(event);\n await saveRoutedTaskEvent(trx, router, event);\n })();\n\n // Router에서 Route를 찾음\n const matched = findRoute(router, \"\", item.namespace);\n if (!matched) {\n await (async () => {\n const event: RoutedTaskEvent = {\n type: \"process:error\",\n task: item,\n timestamp: new Date(),\n info: info,\n reason: \"no_route\",\n };\n\n onEvent(event);\n await saveRoutedTaskEvent(trx, router, event);\n })();\n await trx.commit();\n return;\n }\n\n try {\n await routedAction(matched, item);\n await (async () => {\n const event: RoutedTaskEvent = {\n type: \"process:complete\",\n task: item,\n timestamp: new Date(),\n info: matched.data.info,\n };\n\n onEvent(event);\n await saveRoutedTaskEvent(trx, router, event);\n })();\n } catch (err) {\n let evt: RoutedTaskEvent;\n if (isSonamuTaskError(err)) {\n evt = {\n type: \"process:error\",\n task: item,\n timestamp: new Date(),\n info: matched.data.info,\n reason: err.type,\n error: err.cause ?? err,\n };\n } else if (err instanceof Error) {\n evt = {\n type: \"process:error\",\n task: item,\n timestamp: new Date(),\n info: matched.data.info,\n reason: \"exception\",\n error: err,\n };\n } else {\n evt = {\n type: \"process:error\",\n task: item,\n timestamp: new Date(),\n info: matched.data.info,\n reason: \"exception\",\n error: new Error(`Unknown Error: ${err}`),\n };\n }\n\n onEvent(evt);\n await saveRoutedTaskEvent(trx, router, evt);\n } finally {\n await trx.commit();\n }\n}\n"],"names":["findRoute","isSonamuTaskError","routedAction","saveUnroutedTaskEvent","knex","data","type","insert","event_type","info_id","fn","uuidToBin","info","id","info_name","name","timestamp","into","reason","error_message","error","message","error_stack","stack","Error","saveRoutedTaskEvent","router","queries","matched","task","namespace","push","task_item_id","attempt","where","delete","created_at","createdAt","completed_at","payload","status","retry","maxAttempts","update","updated_at","Promise","all","wrapRemoteTask","onEvent","trx","transaction","event","Date","rawTask","select","from","forUpdate","skipLocked","limit","first","rollback","item","binToUuid","updatedAt","commit","err","evt","cause"],"mappings":"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"}
|
package/dist/tasks/shared.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { MatchedRoute } from "rou3";
|
|
2
|
-
import type { TaskItem, TaskRouterContext, SchedulerInfo } from "../types";
|
|
3
|
-
import { z } from "zod";
|
|
4
|
-
export declare function convertTo<T extends z.ZodType>(schema: T, payload: Buffer | string | any): Promise<z.infer<T>>;
|
|
5
|
-
export declare function routedAction(matched: MatchedRoute<TaskRouterContext & {
|
|
6
|
-
info: SchedulerInfo;
|
|
7
|
-
}>, taskInfo: TaskItem): Promise<void>;
|
|
8
|
-
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/tasks/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE3E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,wBAAsB,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EACjD,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,GAAG,GAC7B,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAkBrB;AAGD,wBAAsB,YAAY,CAChC,OAAO,EAAE,YAAY,CAAC,iBAAiB,GAAG;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC,EAClE,QAAQ,EAAE,QAAQ,iBAsBnB"}
|
package/dist/tasks/shared.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { SonamuTaskError } from "../errors.js";
|
|
2
|
-
// UTF-8 JSON Buffer를 Zod Type으로 변환하는 함수.
|
|
3
|
-
// NOTE: 여기를 잘 처리하면 serialize/parse를 JSON이 아닌 형식으로도 변환할 수 있음.
|
|
4
|
-
export async function convertTo(schema, payload) {
|
|
5
|
-
try {
|
|
6
|
-
if (payload instanceof Buffer) {
|
|
7
|
-
return schema.parseAsync(JSON.parse(payload.toString()));
|
|
8
|
-
}
|
|
9
|
-
if (typeof payload === "string") {
|
|
10
|
-
return schema.parseAsync(JSON.parse(payload));
|
|
11
|
-
}
|
|
12
|
-
return schema.parseAsync(payload);
|
|
13
|
-
} catch (error) {
|
|
14
|
-
if (error instanceof Error) {
|
|
15
|
-
throw new SonamuTaskError("validation", error);
|
|
16
|
-
}
|
|
17
|
-
throw new SonamuTaskError("validation");
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
// Router에서 매칭 후, 모든 TaskItem의 처리
|
|
21
|
-
export async function routedAction(matched, taskInfo) {
|
|
22
|
-
const { data: ctx, params } = matched;
|
|
23
|
-
// 재시도 횟수를 체크함.
|
|
24
|
-
if (ctx.retry.maxAttempts < taskInfo.attempt) {
|
|
25
|
-
throw new SonamuTaskError("max_retries_exceeded");
|
|
26
|
-
}
|
|
27
|
-
// 데이터를 파싱해서 context를 만들고 실제 route 함수를 실행.
|
|
28
|
-
const result = ctx.target({
|
|
29
|
-
taskItem: {
|
|
30
|
-
...taskInfo,
|
|
31
|
-
payload: await convertTo(ctx.schema, taskInfo.payload)
|
|
32
|
-
},
|
|
33
|
-
params,
|
|
34
|
-
retry: ctx.retry
|
|
35
|
-
});
|
|
36
|
-
if (result instanceof Promise) {
|
|
37
|
-
await result;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
//# sourceMappingURL=shared.js.map
|
package/dist/tasks/shared.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/tasks/shared.ts"],"sourcesContent":["import type { MatchedRoute } from \"rou3\";\nimport type { TaskItem, TaskRouterContext, SchedulerInfo } from \"../types\";\nimport { SonamuTaskError } from \"../errors\";\nimport { z } from \"zod\";\n\n// UTF-8 JSON Buffer를 Zod Type으로 변환하는 함수.\n// NOTE: 여기를 잘 처리하면 serialize/parse를 JSON이 아닌 형식으로도 변환할 수 있음.\nexport async function convertTo<T extends z.ZodType>(\n schema: T,\n payload: Buffer | string | any,\n): Promise<z.infer<T>> {\n try {\n if (payload instanceof Buffer) {\n return schema.parseAsync(JSON.parse(payload.toString()));\n }\n\n if (typeof payload === \"string\") {\n return schema.parseAsync(JSON.parse(payload));\n }\n\n return schema.parseAsync(payload);\n } catch (error) {\n if (error instanceof Error) {\n throw new SonamuTaskError(\"validation\", error);\n }\n\n throw new SonamuTaskError(\"validation\");\n }\n}\n\n// Router에서 매칭 후, 모든 TaskItem의 처리\nexport async function routedAction(\n matched: MatchedRoute<TaskRouterContext & { info: SchedulerInfo }>,\n taskInfo: TaskItem,\n) {\n const { data: ctx, params } = matched;\n\n // 재시도 횟수를 체크함.\n if (ctx.retry.maxAttempts < taskInfo.attempt) {\n throw new SonamuTaskError(\"max_retries_exceeded\");\n }\n\n // 데이터를 파싱해서 context를 만들고 실제 route 함수를 실행.\n const result = ctx.target({\n taskItem: {\n ...taskInfo,\n payload: await convertTo(ctx.schema, taskInfo.payload),\n },\n params,\n retry: ctx.retry,\n });\n\n if (result instanceof Promise) {\n await result;\n }\n}\n"],"names":["SonamuTaskError","convertTo","schema","payload","Buffer","parseAsync","JSON","parse","toString","error","Error","routedAction","matched","taskInfo","data","ctx","params","retry","maxAttempts","attempt","result","target","taskItem","Promise"],"mappings":"AAEA,SAASA,eAAe,QAAQ,eAAY;AAG5C,yCAAyC;AACzC,6DAA6D;AAC7D,OAAO,eAAeC,UACpBC,MAAS,EACTC,OAA8B;IAE9B,IAAI;QACF,IAAIA,mBAAmBC,QAAQ;YAC7B,OAAOF,OAAOG,UAAU,CAACC,KAAKC,KAAK,CAACJ,QAAQK,QAAQ;QACtD;QAEA,IAAI,OAAOL,YAAY,UAAU;YAC/B,OAAOD,OAAOG,UAAU,CAACC,KAAKC,KAAK,CAACJ;QACtC;QAEA,OAAOD,OAAOG,UAAU,CAACF;IAC3B,EAAE,OAAOM,OAAO;QACd,IAAIA,iBAAiBC,OAAO;YAC1B,MAAM,IAAIV,gBAAgB,cAAcS;QAC1C;QAEA,MAAM,IAAIT,gBAAgB;IAC5B;AACF;AAEA,iCAAiC;AACjC,OAAO,eAAeW,aACpBC,OAAkE,EAClEC,QAAkB;IAElB,MAAM,EAAEC,MAAMC,GAAG,EAAEC,MAAM,EAAE,GAAGJ;IAE9B,eAAe;IACf,IAAIG,IAAIE,KAAK,CAACC,WAAW,GAAGL,SAASM,OAAO,EAAE;QAC5C,MAAM,IAAInB,gBAAgB;IAC5B;IAEA,0CAA0C;IAC1C,MAAMoB,SAASL,IAAIM,MAAM,CAAC;QACxBC,UAAU;YACR,GAAGT,QAAQ;YACXV,SAAS,MAAMF,UAAUc,IAAIb,MAAM,EAAEW,SAASV,OAAO;QACvD;QACAa;QACAC,OAAOF,IAAIE,KAAK;IAClB;IAEA,IAAIG,kBAAkBG,SAAS;QAC7B,MAAMH;IACR;AACF"}
|