|
| 1 | +export const metadata = { |
| 2 | + title: 'Tasks', |
| 3 | + description: |
| 4 | + "On this page, we'll dive into tasks, and how to connect to them and listen for updates through the Web API.", |
| 5 | +} |
| 6 | + |
| 7 | +# Tasks |
| 8 | + |
| 9 | +Tasks are long-running operations that some users may want to come back to, or leave running in the background. {{ className: 'lead' }} |
| 10 | + |
| 11 | +## Authentication |
| 12 | + |
| 13 | +Connecting to the task endpoint doesn't require any special permissions. However, each task has a list of ACLs that you must have at least one of to connect to the task. |
| 14 | + |
| 15 | +For example, even though you can connect, if you don't have the `system:maintenance:read` ACL, you won't be able to access any of the session/object cleanup tasks. |
| 16 | + |
| 17 | +--- |
| 18 | + |
| 19 | +## Connect {{ tag: 'WS', label: '/api/v1/task' }} |
| 20 | + |
| 21 | +Connecting and listening to task is a multi-stage process. You can listen to more than one task on the same websocket connection. |
| 22 | + |
| 23 | +### Setting up |
| 24 | + |
| 25 | +This is a GET endpoint that upgrades to a Websocket connection upon connection. |
| 26 | + |
| 27 | +When you connect, you'll get a single message: |
| 28 | + |
| 29 | +- `unauthenticated`: There was an error fetching the internal states of your websocket connection, and you won't be able to connect to any tasks. |
| 30 | +- `connect`: You've connect successfully to the endpoint, and you can continue. |
| 31 | + |
| 32 | +### Connecting to a task |
| 33 | + |
| 34 | +Once connected, you can send a message in the following format: |
| 35 | + |
| 36 | +``` |
| 37 | +connect/{task id} |
| 38 | +``` |
| 39 | + |
| 40 | +Where "task id" is the ID of the task you want to connect to. These task IDs are returned by several other endpoints, like import endpoints and task CRUD endpoints. |
| 41 | + |
| 42 | +After you send that message, you'll be connected to the task. |
| 43 | + |
| 44 | +At any point, Drop will send one of the following messages: |
| 45 | + |
| 46 | +### Error event: `error/{task id}/{error title}/{error body}` |
| 47 | + |
| 48 | +This means something has gone wrong with the task, and you should show or handle the error. |
| 49 | + |
| 50 | +If "error title" is "Unknown task", your task ID was invalid, or you do not have the necessary ACLs to access the task. |
| 51 | + |
| 52 | +This is different from an error generated from a task. This error is from Drop itself, not the task. |
| 53 | + |
| 54 | +### Disconnect event: `disconnect/{task id}` |
| 55 | + |
| 56 | +The task has ended, and you'll no longer recieve updates |
| 57 | + |
| 58 | +### Task message: `{ ... JSON object ... }` |
| 59 | + |
| 60 | +If the message isn't one of the two above ones, it'll be a stringified JSON object that represents a task message: |
| 61 | + |
| 62 | +```json |
| 63 | +{ |
| 64 | + "id": "...", |
| 65 | + "name": "My Task", |
| 66 | + "success": false, |
| 67 | + "progress": 34, |
| 68 | + "error": null, |
| 69 | + "log": [ |
| 70 | + "... JSON object ...", |
| 71 | + "... JSON object ...", |
| 72 | + "... more JSON objects ...", |
| 73 | + "... yet another JSON object ..." |
| 74 | + ], |
| 75 | + "reset": false |
| 76 | +}; |
| 77 | +``` |
| 78 | + |
| 79 | +### Task message properties |
| 80 | + |
| 81 | +Here's what they do: |
| 82 | + |
| 83 | +<Properties> |
| 84 | + <Property name="id" type="string"> |
| 85 | + Task ID of this message |
| 86 | + </Property> |
| 87 | + <Property name="name" type="string"> |
| 88 | + User-friendly name of this task. |
| 89 | + </Property> |
| 90 | + <Property name="success" type="string"> |
| 91 | + If `true`, this task has completed without error. |
| 92 | + </Property> |
| 93 | + <Property name="error" type="object"> |
| 94 | + If not `null` or `undefined`, it will be an object: |
| 95 | + ```json |
| 96 | + { |
| 97 | + "title": "My Error", |
| 98 | + "description": "Something has gone terribly wrong." |
| 99 | + } |
| 100 | + ``` |
| 101 | + |
| 102 | + This means the task has errored out with the above error. |
| 103 | + |
| 104 | + </Property> |
| 105 | + <Property name="progress" type="number"> |
| 106 | + A number between 0-100 that represents the progress. Not guaranteed to be between 0-100, but we spit out warnings if it is. |
| 107 | + </Property> |
| 108 | + <Property name="log" type="string[]"> |
| 109 | + An array of log messages. If `reset` is not set (see below), it is a **partial** log message, which means you should append these messages to a local cache of them for display. |
| 110 | + |
| 111 | + Each log message is a JSON stringified object: |
| 112 | + ```json |
| 113 | + { |
| 114 | + "message": "my log line", |
| 115 | + "level": "info", |
| 116 | + "timestamp": "2025-09-23T06:37:19.047Z" |
| 117 | + } |
| 118 | + ``` |
| 119 | + |
| 120 | + The values are fairly self-explanatory. Do note that, on older versions of Drop, `level` is a number rather than a string, so you may need to map it to the string value: |
| 121 | + |
| 122 | + | Number | String | |
| 123 | + | ------ | ------ | |
| 124 | + | 100 | silent | |
| 125 | + | 60 | fatal | |
| 126 | + | 50 | error | |
| 127 | + | 40 | warn | |
| 128 | + | 30 | info | |
| 129 | + | 20 | debug | |
| 130 | + | 10 | trace | |
| 131 | + | 0 | off | |
| 132 | + |
| 133 | + This also serves as a list of all possible `level` values*.* |
| 134 | + |
| 135 | + </Property> |
| 136 | + <Property name="reset" type="boolean"> |
| 137 | + This message is a reset message, meaning it contains a full log history, rather than a partial one. You should overwrite your local log history, rather than appending to it. |
| 138 | + </Property> |
| 139 | +</Properties> |
| 140 | + |
| 141 | +--- |
| 142 | + |
| 143 | +## Fetch all tasks {{ tag: 'GET', label: '/api/v1/admin/task', apilevel: "system", acl: "task:read" }} |
| 144 | + |
| 145 | +<Row> |
| 146 | + <Col> |
| 147 | + |
| 148 | + Fetches all tasks running, recently run, and scheduled for this instance. |
| 149 | + |
| 150 | + <Note> |
| 151 | + The scheduled tasks refer to *task groups*, not individual tasks. These are string IDs for a type of task, like `cleanup:invitations`, rather than a *specific* task, like `cleanup:invitations:{timestamp}`. |
| 152 | + </Note> |
| 153 | + |
| 154 | + </Col> |
| 155 | + <Col sticky> |
| 156 | + |
| 157 | + <CodeGroup title="Request" tag="GET" label="/api/v1/admin/task"> |
| 158 | + |
| 159 | + ```bash {{ title: 'cURL' }} |
| 160 | + curl -G http://localhost:3000/api/v1/admin/task \ |
| 161 | + -H "Authorization: Bearer {token}" |
| 162 | + ``` |
| 163 | + |
| 164 | + ```js |
| 165 | + const response = await fetch("http://localhost:3000/api/v1/admin/task", { |
| 166 | + headers: { |
| 167 | + Authorization: "Bearer {token}" |
| 168 | + }, |
| 169 | + }); |
| 170 | + |
| 171 | + const { runningTasks, historicalTasks, dailyTasks, weeklyTasks } = await response.blob(); |
| 172 | + |
| 173 | + ``` |
| 174 | + |
| 175 | + </CodeGroup> |
| 176 | + |
| 177 | + ```json {{ title: 'Response' }} |
| 178 | + { |
| 179 | + "runningTasks": [], |
| 180 | + "historicalTasks": [ |
| 181 | + { |
| 182 | + "id": "cleanup:invitations:2025-08-23T08:27:15.156Z", |
| 183 | + "taskGroup": "cleanup:invitations", |
| 184 | + "name": "Cleanup Invitations", |
| 185 | + "started": "2025-08-23T08:27:15.156Z", |
| 186 | + "ended": "2025-08-23T08:27:15.258Z", |
| 187 | + "success": true, |
| 188 | + "error": null, |
| 189 | + "progress": 100, |
| 190 | + "log": [ |
| 191 | + "{\"level\":\"info\",\"time\":\"2025-08-23T08:27:15.257Z\",\"msg\":\"Cleaning invitations\"}", |
| 192 | + "{\"level\":\"info\",\"time\":\"2025-08-23T08:27:15.258Z\",\"msg\":\"Done\"}" |
| 193 | + ], |
| 194 | + "acls": [ |
| 195 | + "system:maintenance:read" |
| 196 | + ] |
| 197 | + }, |
| 198 | + { |
| 199 | + "id": "cleanup:sessions:2025-08-23T01:02:47.015Z", |
| 200 | + "taskGroup": "cleanup:sessions", |
| 201 | + "name": "Cleanup Sessions", |
| 202 | + "started": "2025-08-23T01:02:47.016Z", |
| 203 | + "ended": "2025-08-23T01:02:47.132Z", |
| 204 | + "success": true, |
| 205 | + "error": null, |
| 206 | + "progress": 100, |
| 207 | + "log": [ |
| 208 | + "{\"level\":\"info\",\"time\":\"2025-08-23T01:02:47.116Z\",\"msg\":\"Cleaning up sessions\"}", |
| 209 | + "{\"level\":\"info\",\"time\":\"2025-08-23T01:02:47.132Z\",\"msg\":\"Done\"}" |
| 210 | + ], |
| 211 | + "acls": [ |
| 212 | + "system:maintenance:read" |
| 213 | + ] |
| 214 | + }, |
| 215 | + ], |
| 216 | + "dailyTasks": [ |
| 217 | + "cleanup:invitations", |
| 218 | + "cleanup:sessions", |
| 219 | + "check:update" |
| 220 | + ], |
| 221 | + "weeklyTasks": [ |
| 222 | + "cleanup:objects" |
| 223 | + ] |
| 224 | + } |
| 225 | + ``` |
| 226 | + |
| 227 | + </Col> |
| 228 | +</Row> |
| 229 | + |
| 230 | +--- |
| 231 | + |
| 232 | +## Execute scheduled task {{ tag: 'POST', label: '/api/v1/admin/task', apilevel: "system", acl: "task:start" }} |
| 233 | + |
| 234 | +<Row> |
| 235 | + <Col> |
| 236 | + |
| 237 | + This endpoint invokes a scheduled task by the task group name (see above, `dailyTasks` & `weeklyTasks`), and returns the task ID. |
| 238 | + |
| 239 | + Despite not needing the task's ACL to start it, you will need the task's ACL to read it. |
| 240 | + |
| 241 | + ### Request body |
| 242 | + <Properties> |
| 243 | + <Property name="taskGroup" type="string"> |
| 244 | + Name of the task group to start. |
| 245 | + </Property> |
| 246 | + </Properties> |
| 247 | + |
| 248 | + </Col> |
| 249 | + <Col sticky> |
| 250 | + |
| 251 | + <CodeGroup title="Request" tag="POST" label="/api/v1/admin/task"> |
| 252 | + |
| 253 | + ```bash {{ title: 'cURL' }} |
| 254 | + curl -X POST http://localhost:3000/api/v1/admin/task \ |
| 255 | + -H "Authorization: Bearer {token}" \ |
| 256 | + -H "Content-Type: application/json" \ |
| 257 | + -d "{ ... }" |
| 258 | + ``` |
| 259 | + |
| 260 | + ```js |
| 261 | + const response = await fetch("http://localhost:3000/api/v1/admin/task", { |
| 262 | + headers: { |
| 263 | + Authorization: "Bearer {token}" |
| 264 | + }, |
| 265 | + method: "POST", |
| 266 | + body: { |
| 267 | + taskGroup: "..." |
| 268 | + } |
| 269 | + }); |
| 270 | + |
| 271 | + |
| 272 | + ``` |
| 273 | + |
| 274 | + </CodeGroup> |
| 275 | + |
| 276 | + ```json {{ title: 'Response' }} |
| 277 | + { |
| 278 | + "id": "..." |
| 279 | + } |
| 280 | + ``` |
| 281 | + |
| 282 | + </Col> |
| 283 | +</Row> |
| 284 | + |
| 285 | +--- |
| 286 | + |
| 287 | +## Scheduled tasks |
| 288 | + |
| 289 | +This is an exhaustive list of all scheduled tasks, their descriptions, and their tasks groups on Drop instances. It may be out-of-date for new versions. Please file a [report](https://github.com/Drop-OSS/drop-api-docs/issues) if you believe it is out-of-date. |
| 290 | + |
| 291 | +| Task Group | Task Name | Description | |
| 292 | +| --------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | |
| 293 | +| `debug` | Debug Task | May not be implemented; usually removed for release and only added when needing to debug tasks. | |
| 294 | +| `cleanup:invitations` | Cleanup Invitations | Deletes expired invitations from database to save space. Invitations check themselves regardless, this just cleans out old invitations. | |
| 295 | +| `cleanup:objects` | Cleanup Objects | Deletes unreferenced objects from the object backend to save space. | |
| 296 | +| `cleanup:sessions` | Cleanup Sessions | Cleans up expired sessions from the session handler. | |
| 297 | +| `check:update` | Check for Update | Checks if there is an update for Drop available, and if so, send a notification to admins. | |
0 commit comments