@things-factory/scheduler 7.1.34
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/CHANGELOG.md +8 -0
- package/client/bootstrap.ts +1 -0
- package/client/index.ts +0 -0
- package/client/pages/scheduler/popup-crontab-input.ts +75 -0
- package/client/pages/scheduler/schedule-list-page.ts +326 -0
- package/client/pages/scheduler/schedule-popup.ts +484 -0
- package/client/route.ts +7 -0
- package/client/tsconfig.json +11 -0
- package/client/types.ts +34 -0
- package/dist-client/bootstrap.d.ts +1 -0
- package/dist-client/bootstrap.js +2 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/index.d.ts +0 -0
- package/dist-client/index.js +2 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/pages/scheduler/popup-crontab-input.d.ts +12 -0
- package/dist-client/pages/scheduler/popup-crontab-input.js +77 -0
- package/dist-client/pages/scheduler/popup-crontab-input.js.map +1 -0
- package/dist-client/pages/scheduler/schedule-list-page.d.ts +42 -0
- package/dist-client/pages/scheduler/schedule-list-page.js +326 -0
- package/dist-client/pages/scheduler/schedule-list-page.js.map +1 -0
- package/dist-client/pages/scheduler/schedule-popup.d.ts +25 -0
- package/dist-client/pages/scheduler/schedule-popup.js +457 -0
- package/dist-client/pages/scheduler/schedule-popup.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +8 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-client/types.d.ts +33 -0
- package/dist-client/types.js +2 -0
- package/dist-client/types.js.map +1 -0
- package/dist-server/controllers/index.d.ts +0 -0
- package/dist-server/controllers/index.js +1 -0
- package/dist-server/controllers/index.js.map +1 -0
- package/dist-server/index.d.ts +2 -0
- package/dist-server/index.js +6 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/routes.d.ts +1 -0
- package/dist-server/routes.js +25 -0
- package/dist-server/routes.js.map +1 -0
- package/dist-server/service/index.d.ts +5 -0
- package/dist-server/service/index.js +21 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/schedule/index.d.ts +6 -0
- package/dist-server/service/schedule/index.js +10 -0
- package/dist-server/service/schedule/index.js.map +1 -0
- package/dist-server/service/schedule/schedule-mutation.d.ts +6 -0
- package/dist-server/service/schedule/schedule-mutation.js +55 -0
- package/dist-server/service/schedule/schedule-mutation.js.map +1 -0
- package/dist-server/service/schedule/schedule-query.d.ts +6 -0
- package/dist-server/service/schedule/schedule-query.js +70 -0
- package/dist-server/service/schedule/schedule-query.js.map +1 -0
- package/dist-server/service/schedule/schedule-type.d.ts +75 -0
- package/dist-server/service/schedule/schedule-type.js +281 -0
- package/dist-server/service/schedule/schedule-type.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/helps/scheduler/assets/scheduler-explains.png +0 -0
- package/helps/scheduler/assets/scheduler-service-msa.png +0 -0
- package/helps/scheduler/assets/scheduler-service-openapi.png +0 -0
- package/helps/scheduler/assets/scheduler-service-scalable.png +0 -0
- package/helps/scheduler/assets/updated-scheduler-diagram-periodic.png +0 -0
- package/helps/scheduler/assets/updated-scheduler-diagram-pubsub.png +0 -0
- package/helps/scheduler/scheduler.ko.md +185 -0
- package/helps/scheduler/scheduler.md +186 -0
- package/helps/scheduler/scheduler.zh.md +185 -0
- package/package.json +38 -0
- package/server/controllers/index.ts +0 -0
- package/server/index.ts +3 -0
- package/server/routes.ts +28 -0
- package/server/service/index.ts +25 -0
- package/server/service/schedule/index.ts +7 -0
- package/server/service/schedule/schedule-mutation.ts +34 -0
- package/server/service/schedule/schedule-query.ts +64 -0
- package/server/service/schedule/schedule-type.ts +194 -0
- package/server/tsconfig.json +10 -0
- package/things-factory.config.js +8 -0
- package/translations/en.json +9 -0
- package/translations/ja.json +9 -0
- package/translations/ko.json +9 -0
- package/translations/ms.json +9 -0
- package/translations/zh.json +9 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# 스케줄러 서비스
|
|
2
|
+
|
|
3
|
+
- Scheduler에 등록되는 모든 이벤트들은 cron을 포함한 여러 형태의 스케줄 타입 및 값이 지정
|
|
4
|
+
- 사용자가 지정한 스케줄 형태에 따라서 이벤트가 호출되며, 일반적으로 호출된 이벤트는 사용자가 등록 시에 지정한 rest api를 호출
|
|
5
|
+
- 호출된 이벤트가 실패할 경우 정책에 따라서 일정 시간 이후 재시도 수행
|
|
6
|
+
- 스케줄러 처리의 부하를 분산하기 위해서 새롭게 설계된 구조로서 스케줄러는 데이터베이스 기반의 큐 구조를 사용하여 모든 스케줄 데이터를 관리
|
|
7
|
+
|
|
8
|
+
### 스케줄러의 주기적 처리에 대한 Diagram
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
- 구조가 간결하고 추가적인 다른 서비스 없이 운용 가능하다는 점이 장점
|
|
13
|
+
- 각 인스턴스가 휴지 기간 없이 주기적으로 깨어나서 데이터베이스 내에 스케줄 큐를 확인해야 한다는 점이 단점.
|
|
14
|
+
|
|
15
|
+
### (대안) 스케줄러의 깨어나는 시점을 또다른 모니터링 인스턴스가 주기적으로 확인해서 모든 스케줄러에게 Publish하는 구조
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+
|
|
19
|
+
- 모든 인스턴스는 모니터링 인스턴스를 통해서 받는 다음 스케줄의 타임스탬프 정보에 의해서 스케줄 처리를 수행.
|
|
20
|
+
- 추가적인 서비스(redis) 필요하며, 개별 인스턴스는 지속적으로 다음 스케줄에 대한 정보를 가지고 있어야 함.
|
|
21
|
+
|
|
22
|
+
## MSA 기반의 스케줄러 서비스
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
- 기존의 어플리케이션 구조에서 스케줄링 잡을 처리하는 스케줄러 서비스가 클라우드 기반의 수평 스케일링 구조에서 기능 수행이 불가능.
|
|
27
|
+
- 별도의 스케줄러 서비스가 필요. 이러한 스케줄 작업을 수행하는 서비스는 다수 존재하지만 스케줄러 역할만을 수행하는 분리된 서비스가 없음.
|
|
28
|
+
- 클라우드 환경에서 사용 가능한 수평적인 확장이 가능한 서비스 개발이 필요.
|
|
29
|
+
|
|
30
|
+
## 서비스 개요
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
- 스케줄러 서비스는 Restful 기반의 수평 확장이 가능한 스케줄러 서비스.
|
|
35
|
+
- MSA 기반의 어플리케이션 환경에서 기존 어플리케이션이 수행하는 스케줄링 모듈에 대해서, 별도의 스케줄링 서비스를 분리해서 제공하는 서비스를 제공합니다.
|
|
36
|
+
|
|
37
|
+
## 사용 가능한 용도
|
|
38
|
+
|
|
39
|
+
- 크론(cron) 기반의 스케줄잡(Schedule Job) 핸들러
|
|
40
|
+
- 특정한 날짜 혹은 특정한 주기로 실행되는 태스크 실행 엔진
|
|
41
|
+
- 특정한 이벤트를 등록 관리하고, 이벤트를 기반으로 특정 기능을 실행하거나 데이터를 전달하는 브로커
|
|
42
|
+
|
|
43
|
+
### Schedule
|
|
44
|
+
|
|
45
|
+
#### Format
|
|
46
|
+
|
|
47
|
+
스케줄을 등록하기 위한 포맷의 예는 다음과 같습니다.
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"name": "bbb",
|
|
52
|
+
"client": {
|
|
53
|
+
"operation": "op#1",
|
|
54
|
+
"application": "chef",
|
|
55
|
+
"group": "system",
|
|
56
|
+
"key": "12345678",
|
|
57
|
+
"type": "scheduler"
|
|
58
|
+
},
|
|
59
|
+
"type": "cron",
|
|
60
|
+
"schedule": "30 * * * * *",
|
|
61
|
+
"timezone": "Asia/Seoul",
|
|
62
|
+
"task": {
|
|
63
|
+
"type": "rest",
|
|
64
|
+
"connection": {
|
|
65
|
+
"host": "http://localhost:3000/api/unstable/run-scenario/DELAY-TEST-9",
|
|
66
|
+
"headers": { "Content-Type": "application/json", "accept": "*/*", "Authorization": "Bearer ..." }
|
|
67
|
+
},
|
|
68
|
+
"data": { "instanceName": "delay-test-999", "variables": {} },
|
|
69
|
+
"history_check": false,
|
|
70
|
+
"failed_policy": "retry",
|
|
71
|
+
"retry_wait": 60
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- name: 스케줄의 이름
|
|
77
|
+
- client: 클라이언트 정보를 표현합니다. 실제 스케줄은 5개의 요소가 모두 일치할 때 동일한 스케줄로 인식
|
|
78
|
+
- operation: 공정과 같은 별도의 스케줄 용도를 표현
|
|
79
|
+
- application: 클라이언트 어플리케이션 이름
|
|
80
|
+
- group: 도메인 정보
|
|
81
|
+
- key: 스케줄 구분을 위한 별도의 키
|
|
82
|
+
- 타입: 해당 스케줄 자체에 대한 리소스 타입
|
|
83
|
+
- type: 스케줄 타입으로서 크게, cron, now, date, delay, delay-recur으로 구성됩니다. 자세한 설명은 다음 항목을 참조
|
|
84
|
+
- schedule: 스케줄 타입에 따라 별도의 문자열이 지정됩니다. 자세한 설명은 아래 'Scheduler Type'을 참조.
|
|
85
|
+
- timezone: 스케줄 처리를 위한 타임존 문자열(예. Asiz/Seoul)을 지정.
|
|
86
|
+
- task: 해당 스케줄이 처리되어야할 때 필요한 태스크 정보를 포함.
|
|
87
|
+
- type: 태스크의 타입으로서, 크게 rest, kafka, redis 중 하나를 지정. rest의 경우 post만 지원합니다.
|
|
88
|
+
- connection: 해당 태스크가 수행되기 위한 연결 정보
|
|
89
|
+
- host: 서버 연결 정보
|
|
90
|
+
- topic: kafka와 redis 타입일 때 지정.
|
|
91
|
+
- headers: rest 타입일 경우 선택적으로 지정.
|
|
92
|
+
- data: 해당 태스크 수행 시 전달되어야 하는데이터를 지정
|
|
93
|
+
- history_check: 스케줄의 등록, 실행, 삭제, 재실행에 대한 히스토리를 별도의 DB에 저장.
|
|
94
|
+
|
|
95
|
+
### Schedule Type
|
|
96
|
+
|
|
97
|
+
- delay: 특정한 시간(초) 동안 대기 후에 스케줄을 실행합니다.
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
...
|
|
102
|
+
"type": "delay",
|
|
103
|
+
"schedule": "50",
|
|
104
|
+
"timezone": "Asia/Seoul",
|
|
105
|
+
...
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- delay-recur: 특정 시간(초) 동안 대기 후에 실행되는 스케줄을 반복 합니다.
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
...
|
|
114
|
+
"type": "delay-recur",
|
|
115
|
+
"schedule": "50",
|
|
116
|
+
"timezone": "Asia/Seoul",
|
|
117
|
+
...
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- cron: cron format을 기반으로 스케줄이 동작합니다.
|
|
122
|
+
|
|
123
|
+
- 기본적인 5개 포맷을 사용합니다.
|
|
124
|
+
- 초 단위 스케줄리을 실행하기 위해서는 6개 시간 요소가 필요하면, 첫번째 요소가 초를 지정합니다.
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
...
|
|
129
|
+
"type": "cron",
|
|
130
|
+
"schedule": "0 * * * *",
|
|
131
|
+
"timezone": "Asia/Seoul",
|
|
132
|
+
...
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
- date: 특정한 일자 및 시간을 지정.(ISO 포맷, YYYY-MM-DDThh:mm:ss)
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
...
|
|
141
|
+
"type": "date",
|
|
142
|
+
"schedule": "2023-04-05T12:30:00",
|
|
143
|
+
"timezone": "Asia/Seoul",
|
|
144
|
+
...
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- now: 바로 지금 해당 스케줄을 실행
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
...
|
|
152
|
+
"type": "now",
|
|
153
|
+
"schedule": "",
|
|
154
|
+
"timezone": "Asia/Seoul",
|
|
155
|
+
...
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Task Type
|
|
160
|
+
|
|
161
|
+
- Rest
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
...
|
|
166
|
+
"task": {
|
|
167
|
+
"type": "rest",
|
|
168
|
+
"connection": {"host": "http://localhost:3000/api/unstable/run-scenario/test-scenario-1", "headers": {"Content-Type": "application/json", "accept": "*/*"}},
|
|
169
|
+
"data": {"instanceName": "test-scenario-1", "variables": {}}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
- Kafka & Redis
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
...
|
|
179
|
+
"task": {
|
|
180
|
+
"type": "kafka",
|
|
181
|
+
"connection": {"host": "localhost:9092", "topic": "example-topic"},
|
|
182
|
+
"data": { ... }
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Scheduler Service
|
|
2
|
+
|
|
3
|
+
- All events registered in the Scheduler are specified with various schedule types and values, including cron.
|
|
4
|
+
- Events are invoked based on the schedule type specified by the user, and typically, the invoked event calls the REST API designated during registration.
|
|
5
|
+
- If an invoked event fails, it retries after a certain period, as defined by the policy.
|
|
6
|
+
- To distribute the load of scheduler processing, a newly designed structure uses a database-based queue to manage all schedule data.
|
|
7
|
+
|
|
8
|
+
### Diagram for Periodic Processing in the Scheduler
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
- **Advantages**: The structure is simple and can be operated without additional services.
|
|
13
|
+
- **Disadvantages**: Each instance must periodically wake up and check the schedule queue in the database without any idle period.
|
|
14
|
+
|
|
15
|
+
### Alternative: Structure Where a Monitoring Instance Publishes Wake-Up Times to All Schedulers
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+
|
|
19
|
+
- All instances process schedules based on the next schedule timestamp information received from a monitoring instance.
|
|
20
|
+
- **Requirements**: Additional services (e.g., Redis) are necessary, and each instance must continuously hold information about the next schedule.
|
|
21
|
+
|
|
22
|
+
## Scheduler Service in MSA
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
- The traditional application structure for processing scheduling jobs cannot function in a cloud-based horizontal scaling architecture.
|
|
27
|
+
- A separate scheduler service is needed. While there are many services for such tasks, there isn’t a dedicated service solely for the role of scheduling.
|
|
28
|
+
- A scalable service that can be horizontally expanded in a cloud environment is required.
|
|
29
|
+
|
|
30
|
+
## Service Overview
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
- Scheduler service is a horizontally scalable scheduling service based on RESTful architecture.
|
|
35
|
+
- It provides a service that separates scheduling modules from existing applications in MSA-based environments.
|
|
36
|
+
|
|
37
|
+
## Usable Scenarios
|
|
38
|
+
|
|
39
|
+
- **Cron-Based Schedule Job Handlers**: For processing tasks at specific intervals.
|
|
40
|
+
- **Task Execution Engines**: For executing tasks on specific dates or at specific intervals.
|
|
41
|
+
- **Event-Driven Task Handlers**: For registering and managing events, and executing specific tasks or transferring data based on those events.
|
|
42
|
+
|
|
43
|
+
### Schedule
|
|
44
|
+
|
|
45
|
+
#### Format
|
|
46
|
+
|
|
47
|
+
An example of the format for registering a schedule is as follows:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"name": "bbb",
|
|
52
|
+
"client": {
|
|
53
|
+
"operation": "op#1",
|
|
54
|
+
"application": "chef",
|
|
55
|
+
"group": "system",
|
|
56
|
+
"key": "12345678",
|
|
57
|
+
"type": "scheduler"
|
|
58
|
+
},
|
|
59
|
+
"type": "cron",
|
|
60
|
+
"schedule": "30 * * * * *",
|
|
61
|
+
"timezone": "Asia/Seoul",
|
|
62
|
+
"task": {
|
|
63
|
+
"type": "rest",
|
|
64
|
+
"connection": {
|
|
65
|
+
"host": "http://localhost:3000/api/unstable/run-scenario/DELAY-TEST-9",
|
|
66
|
+
"headers": { "Content-Type": "application/json", "accept": "*/*", "Authorization": "Bearer ..." }
|
|
67
|
+
},
|
|
68
|
+
"data": { "instanceName": "delay-test-999", "variables": {} },
|
|
69
|
+
"history_check": false,
|
|
70
|
+
"failed_policy": "retry",
|
|
71
|
+
"retry_wait": 60
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- **name**: Name of the schedule.
|
|
77
|
+
- **client**: Represents client information. A schedule is recognized as the same only if all five elements match.
|
|
78
|
+
- **operation**: Represents a specific schedule purpose, like a process.
|
|
79
|
+
- **application**: Name of the client application.
|
|
80
|
+
- **group**: Domain information.
|
|
81
|
+
- **key**: A separate key for schedule distinction.
|
|
82
|
+
- **type**: Resource type of the schedule itself.
|
|
83
|
+
- **type**: Main types include `cron`, `now`, `date`, `delay`, and `delay-recur`. Detailed descriptions are in the "Scheduler Type" section.
|
|
84
|
+
- **schedule**: A string specified based on the schedule type. See "Scheduler Type" for details.
|
|
85
|
+
- **timezone**: Time zone string for schedule processing (e.g., `Asia/Seoul`).
|
|
86
|
+
- **task**: Contains the necessary task information to execute when the schedule is triggered.
|
|
87
|
+
- **type**: Specifies the type of task, such as `rest`, `kafka`, or `redis`. For `rest`, only POST is supported.
|
|
88
|
+
- **connection**: Connection information for task execution.
|
|
89
|
+
- **host**: Server connection information.
|
|
90
|
+
- **topic**: Used for `kafka` and `redis` types.
|
|
91
|
+
- **headers**: Optional for `rest` type.
|
|
92
|
+
- **data**: Specifies the data to be passed during task execution.
|
|
93
|
+
- **history_check**: Saves the history of schedule registration, execution, deletion, and re-execution in a separate database.
|
|
94
|
+
|
|
95
|
+
### Schedule Type
|
|
96
|
+
|
|
97
|
+
- **delay**: Waits for a specific time (in seconds) before executing the schedule.
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
...
|
|
102
|
+
"type": "delay",
|
|
103
|
+
"schedule": "50",
|
|
104
|
+
"timezone": "Asia/Seoul",
|
|
105
|
+
...
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- **delay-recur**: Repeats a schedule after waiting for a specific time (in seconds).
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
...
|
|
114
|
+
"type": "delay-recur",
|
|
115
|
+
"schedule": "50",
|
|
116
|
+
"timezone": "Asia/Seoul",
|
|
117
|
+
...
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- **cron**: Operates based on the cron format.
|
|
122
|
+
|
|
123
|
+
- Uses the basic five-element format.
|
|
124
|
+
- For second-level schedules, a six-element format is required, where the first element specifies seconds.
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
...
|
|
129
|
+
"type": "cron",
|
|
130
|
+
"schedule": "0 * * * *",
|
|
131
|
+
"timezone": "Asia/Seoul",
|
|
132
|
+
...
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
- **date**: Specifies a specific date and time (ISO format, `YYYY-MM-DDThh:mm:ss`).
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
...
|
|
141
|
+
"type": "date",
|
|
142
|
+
"schedule": "2023-04-05T12:30:00",
|
|
143
|
+
"timezone": "Asia/Seoul",
|
|
144
|
+
...
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- **now**: Executes the schedule immediately.
|
|
149
|
+
|
|
150
|
+
```json
|
|
151
|
+
{
|
|
152
|
+
...
|
|
153
|
+
"type": "now",
|
|
154
|
+
"schedule": "",
|
|
155
|
+
"timezone": "Asia/Seoul",
|
|
156
|
+
...
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Task Type
|
|
161
|
+
|
|
162
|
+
- **Rest**
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
...
|
|
167
|
+
"task": {
|
|
168
|
+
"type": "rest",
|
|
169
|
+
"connection": {"host": "http://localhost:3000/api/unstable/run-scenario/test-scenario-1", "headers": {"Content-Type": "application/json", "accept": "*/*"}},
|
|
170
|
+
"data": {"instanceName": "test-scenario-1", "variables": {}}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
- **Kafka & Redis**
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
...
|
|
180
|
+
"task": {
|
|
181
|
+
"type": "kafka",
|
|
182
|
+
"connection": {"host": "localhost:9092", "topic": "example-topic"},
|
|
183
|
+
"data": { ... }
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
```
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# 스케줄러 서비스
|
|
2
|
+
|
|
3
|
+
- Scheduler에 등록되는 모든 이벤트들은 cron을 포함한 여러 형태의 스케줄 타입 및 값이 지정
|
|
4
|
+
- 사용자가 지정한 스케줄 형태에 따라서 이벤트가 호출되며, 일반적으로 호출된 이벤트는 사용자가 등록 시에 지정한 rest api를 호출
|
|
5
|
+
- 호출된 이벤트가 실패할 경우 정책에 따라서 일정 시간 이후 재시도 수행
|
|
6
|
+
- 스케줄러 처리의 부하를 분산하기 위해서 새롭게 설계된 구조로서 스케줄러는 데이터베이스 기반의 큐 구조를 사용하여 모든 스케줄 데이터를 관리
|
|
7
|
+
|
|
8
|
+
### 스케줄러의 주기적 처리에 대한 Diagram
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
- 구조가 간결하고 추가적인 다른 서비스 없이 운용 가능하다는 점이 장점
|
|
13
|
+
- 각 인스턴스가 휴지 기간 없이 주기적으로 깨어나서 데이터베이스 내에 스케줄 큐를 확인해야 한다는 점이 단점.
|
|
14
|
+
|
|
15
|
+
### (대안) 스케줄러의 깨어나는 시점을 또다른 모니터링 인스턴스가 주기적으로 확인해서 모든 스케줄러에게 Publish하는 구조
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+
|
|
19
|
+
- 모든 인스턴스는 모니터링 인스턴스를 통해서 받는 다음 스케줄의 타임스탬프 정보에 의해서 스케줄 처리를 수행.
|
|
20
|
+
- 추가적인 서비스(redis) 필요하며, 개별 인스턴스는 지속적으로 다음 스케줄에 대한 정보를 가지고 있어야 함.
|
|
21
|
+
|
|
22
|
+
## MSA 기반의 스케줄러 서비스
|
|
23
|
+
|
|
24
|
+

|
|
25
|
+
|
|
26
|
+
- 기존의 어플리케이션 구조에서 스케줄링 잡을 처리하는 스케줄러 서비스가 클라우드 기반의 수평 스케일링 구조에서 기능 수행이 불가능.
|
|
27
|
+
- 별도의 스케줄러 서비스가 필요. 이러한 스케줄 작업을 수행하는 서비스는 다수 존재하지만 스케줄러 역할만을 수행하는 분리된 서비스가 없음.
|
|
28
|
+
- 클라우드 환경에서 사용 가능한 수평적인 확장이 가능한 서비스 개발이 필요.
|
|
29
|
+
|
|
30
|
+
## 서비스 개요
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
- 스케줄러 서비스는 Restful 기반의 수평 확장이 가능한 스케줄러 서비스.
|
|
35
|
+
- MSA 기반의 어플리케이션 환경에서 기존 어플리케이션이 수행하는 스케줄링 모듈에 대해서, 별도의 스케줄링 서비스를 분리해서 제공하는 서비스를 제공합니다.
|
|
36
|
+
|
|
37
|
+
## 사용 가능한 용도
|
|
38
|
+
|
|
39
|
+
- 크론(cron) 기반의 스케줄잡(Schedule Job) 핸들러
|
|
40
|
+
- 특정한 날짜 혹은 특정한 주기로 실행되는 태스크 실행 엔진
|
|
41
|
+
- 특정한 이벤트를 등록 관리하고, 이벤트를 기반으로 특정 기능을 실행하거나 데이터를 전달하는 브로커
|
|
42
|
+
|
|
43
|
+
### Schedule
|
|
44
|
+
|
|
45
|
+
#### Format
|
|
46
|
+
|
|
47
|
+
스케줄을 등록하기 위한 포맷의 예는 다음과 같습니다.
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"name": "bbb",
|
|
52
|
+
"client": {
|
|
53
|
+
"operation": "op#1",
|
|
54
|
+
"application": "chef",
|
|
55
|
+
"group": "system",
|
|
56
|
+
"key": "12345678",
|
|
57
|
+
"type": "scheduler"
|
|
58
|
+
},
|
|
59
|
+
"type": "cron",
|
|
60
|
+
"schedule": "30 * * * * *",
|
|
61
|
+
"timezone": "Asia/Seoul",
|
|
62
|
+
"task": {
|
|
63
|
+
"type": "rest",
|
|
64
|
+
"connection": {
|
|
65
|
+
"host": "http://localhost:3000/api/unstable/run-scenario/DELAY-TEST-9",
|
|
66
|
+
"headers": { "Content-Type": "application/json", "accept": "*/*", "Authorization": "Bearer ..." }
|
|
67
|
+
},
|
|
68
|
+
"data": { "instanceName": "delay-test-999", "variables": {} },
|
|
69
|
+
"history_check": false,
|
|
70
|
+
"failed_policy": "retry",
|
|
71
|
+
"retry_wait": 60
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- name: 스케줄의 이름
|
|
77
|
+
- client: 클라이언트 정보를 표현합니다. 실제 스케줄은 5개의 요소가 모두 일치할 때 동일한 스케줄로 인식
|
|
78
|
+
- operation: 공정과 같은 별도의 스케줄 용도를 표현
|
|
79
|
+
- application: 클라이언트 어플리케이션 이름
|
|
80
|
+
- group: 도메인 정보
|
|
81
|
+
- key: 스케줄 구분을 위한 별도의 키
|
|
82
|
+
- 타입: 해당 스케줄 자체에 대한 리소스 타입
|
|
83
|
+
- type: 스케줄 타입으로서 크게, cron, now, date, delay, delay-recur으로 구성됩니다. 자세한 설명은 다음 항목을 참조
|
|
84
|
+
- schedule: 스케줄 타입에 따라 별도의 문자열이 지정됩니다. 자세한 설명은 아래 'Scheduler Type'을 참조.
|
|
85
|
+
- timezone: 스케줄 처리를 위한 타임존 문자열(예. Asiz/Seoul)을 지정.
|
|
86
|
+
- task: 해당 스케줄이 처리되어야할 때 필요한 태스크 정보를 포함.
|
|
87
|
+
- type: 태스크의 타입으로서, 크게 rest, kafka, redis 중 하나를 지정. rest의 경우 post만 지원합니다.
|
|
88
|
+
- connection: 해당 태스크가 수행되기 위한 연결 정보
|
|
89
|
+
- host: 서버 연결 정보
|
|
90
|
+
- topic: kafka와 redis 타입일 때 지정.
|
|
91
|
+
- headers: rest 타입일 경우 선택적으로 지정.
|
|
92
|
+
- data: 해당 태스크 수행 시 전달되어야 하는데이터를 지정
|
|
93
|
+
- history_check: 스케줄의 등록, 실행, 삭제, 재실행에 대한 히스토리를 별도의 DB에 저장.
|
|
94
|
+
|
|
95
|
+
### Schedule Type
|
|
96
|
+
|
|
97
|
+
- delay: 특정한 시간(초) 동안 대기 후에 스케줄을 실행합니다.
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
...
|
|
102
|
+
"type": "delay",
|
|
103
|
+
"schedule": "50",
|
|
104
|
+
"timezone": "Asia/Seoul",
|
|
105
|
+
...
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- delay-recur: 특정 시간(초) 동안 대기 후에 실행되는 스케줄을 반복 합니다.
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
...
|
|
114
|
+
"type": "delay-recur",
|
|
115
|
+
"schedule": "50",
|
|
116
|
+
"timezone": "Asia/Seoul",
|
|
117
|
+
...
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- cron: cron format을 기반으로 스케줄이 동작합니다.
|
|
122
|
+
|
|
123
|
+
- 기본적인 5개 포맷을 사용합니다.
|
|
124
|
+
- 초 단위 스케줄리을 실행하기 위해서는 6개 시간 요소가 필요하면, 첫번째 요소가 초를 지정합니다.
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
...
|
|
129
|
+
"type": "cron",
|
|
130
|
+
"schedule": "0 * * * *",
|
|
131
|
+
"timezone": "Asia/Seoul",
|
|
132
|
+
...
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
- date: 특정한 일자 및 시간을 지정.(ISO 포맷, YYYY-MM-DDThh:mm:ss)
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
...
|
|
141
|
+
"type": "date",
|
|
142
|
+
"schedule": "2023-04-05T12:30:00",
|
|
143
|
+
"timezone": "Asia/Seoul",
|
|
144
|
+
...
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- now: 바로 지금 해당 스케줄을 실행
|
|
149
|
+
```json
|
|
150
|
+
{
|
|
151
|
+
...
|
|
152
|
+
"type": "now",
|
|
153
|
+
"schedule": "",
|
|
154
|
+
"timezone": "Asia/Seoul",
|
|
155
|
+
...
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Task Type
|
|
160
|
+
|
|
161
|
+
- Rest
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
...
|
|
166
|
+
"task": {
|
|
167
|
+
"type": "rest",
|
|
168
|
+
"connection": {"host": "http://localhost:3000/api/unstable/run-scenario/test-scenario-1", "headers": {"Content-Type": "application/json", "accept": "*/*"}},
|
|
169
|
+
"data": {"instanceName": "test-scenario-1", "variables": {}}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
- Kafka & Redis
|
|
175
|
+
|
|
176
|
+
```json
|
|
177
|
+
{
|
|
178
|
+
...
|
|
179
|
+
"task": {
|
|
180
|
+
"type": "kafka",
|
|
181
|
+
"connection": {"host": "localhost:9092", "topic": "example-topic"},
|
|
182
|
+
"data": { ... }
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@things-factory/scheduler",
|
|
3
|
+
"version": "7.1.34",
|
|
4
|
+
"main": "dist-server/index.js",
|
|
5
|
+
"browser": "dist-client/index.js",
|
|
6
|
+
"things-factory": true,
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"author": "heartyoh <heartyoh@hatiolab.com>",
|
|
9
|
+
"description": "connector module for scheduler service",
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public",
|
|
12
|
+
"@things-factory:registry": "https://registry.npmjs.org"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/hatiolab/things-factory.git",
|
|
17
|
+
"directory": "packages/scheduler"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "npm run build:server && npm run build:client",
|
|
21
|
+
"copy:files": "copyfiles -e \"./client/**/*.{ts,js,json}\" -u 1 \"./client/**/*\" dist-client",
|
|
22
|
+
"build:client": "npm run copy:files && npx tsc --p ./client/tsconfig.json",
|
|
23
|
+
"build:server": "npx tsc --p ./server/tsconfig.json",
|
|
24
|
+
"clean:client": "npx rimraf dist-client",
|
|
25
|
+
"clean:server": "npx rimraf dist-server",
|
|
26
|
+
"clean": "npm run clean:server && npm run clean:client",
|
|
27
|
+
"migration:create": "node ../../node_modules/typeorm/cli.js migration:create ./server/migrations/migration"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@operato/graphql": "^7.0.0",
|
|
31
|
+
"@operato/input": "^7.0.0",
|
|
32
|
+
"@operato/shell": "^7.0.0",
|
|
33
|
+
"@things-factory/auth-base": "^7.1.33",
|
|
34
|
+
"@things-factory/scheduler-client": "^7.1.34",
|
|
35
|
+
"@things-factory/shell": "^7.1.24"
|
|
36
|
+
},
|
|
37
|
+
"gitHead": "22830c9e51c9fffb3c95d1d1f8cacc7706f7d2d1"
|
|
38
|
+
}
|
|
File without changes
|
package/server/index.ts
ADDED
package/server/routes.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const debug = require('debug')('things-factory:scheduler:routes')
|
|
2
|
+
|
|
3
|
+
process.on('bootstrap-module-global-public-route' as any, (app, globalPublicRouter) => {
|
|
4
|
+
/*
|
|
5
|
+
* can add global public routes to application (auth not required, tenancy not required)
|
|
6
|
+
*
|
|
7
|
+
* ex) routes.get('/path', async(context, next) => {})
|
|
8
|
+
* ex) routes.post('/path', async(context, next) => {})
|
|
9
|
+
*/
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
process.on('bootstrap-module-global-private-route' as any, (app, globalPrivateRouter) => {
|
|
13
|
+
/*
|
|
14
|
+
* can add global private routes to application (auth required, tenancy not required)
|
|
15
|
+
*/
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
process.on('bootstrap-module-domain-public-route' as any, (app, domainPublicRouter) => {
|
|
19
|
+
/*
|
|
20
|
+
* can add domain public routes to application (auth not required, tenancy required)
|
|
21
|
+
*/
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
process.on('bootstrap-module-domain-private-route' as any, (app, domainPrivateRouter) => {
|
|
25
|
+
/*
|
|
26
|
+
* can add domain private routes to application (auth required, tenancy required)
|
|
27
|
+
*/
|
|
28
|
+
})
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/* EXPORT ENTITY TYPES */
|
|
2
|
+
|
|
3
|
+
/* IMPORT ENTITIES AND RESOLVERS */
|
|
4
|
+
import {
|
|
5
|
+
entities as SchedulerEntities,
|
|
6
|
+
resolvers as SchedulerResolvers,
|
|
7
|
+
subscribers as SchedulerSubscribers
|
|
8
|
+
} from './schedule'
|
|
9
|
+
|
|
10
|
+
export const entities = [
|
|
11
|
+
/* ENTITIES */
|
|
12
|
+
...SchedulerEntities
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
export const subscribers = [
|
|
16
|
+
/* SUBSCRIBERS */
|
|
17
|
+
...SchedulerSubscribers
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
export const schema = {
|
|
21
|
+
resolverClasses: [
|
|
22
|
+
/* RESOLVER CLASSES */
|
|
23
|
+
...SchedulerResolvers
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Schedule } from './schedule-type'
|
|
2
|
+
import { ScheduleQuery } from './schedule-query'
|
|
3
|
+
import { ScheduleMutation } from './schedule-mutation'
|
|
4
|
+
|
|
5
|
+
export const entities = [Schedule]
|
|
6
|
+
export const resolvers = [ScheduleQuery, ScheduleMutation]
|
|
7
|
+
export const subscribers = []
|