feat: add task documentation

This commit is contained in:
DecDuck
2025-08-23 19:17:07 +10:00
parent b77660b913
commit 88e2315c3e
3 changed files with 304 additions and 7 deletions

297
src/app/web/tasks/page.mdx Normal file
View File

@@ -0,0 +1,297 @@
export const metadata = {
title: 'Tasks',
description:
"On this page, we'll dive into tasks, and how to connect to them and listen for updates through the Web API.",
}
# Tasks
Tasks are long-running operations that some users may want to come back to, or leave running in the background. {{ className: 'lead' }}
## Authentication
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.
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.
---
## Connect {{ tag: 'WS', label: '/api/v1/task' }}
Connecting and listening to task is a multi-stage process. You can listen to more than one task on the same websocket connection.
### Setting up
This is a GET endpoint that upgrades to a Websocket connection upon connection.
When you connect, you'll get a single message:
- `unauthenticated`: There was an error fetching the internal states of your websocket connection, and you won't be able to connect to any tasks.
- `connect`: You've connect successfully to the endpoint, and you can continue.
### Connecting to a task
Once connected, you can send a message in the following format:
```
connect/{task id}
```
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.
After you send that message, you'll be connected to the task.
At any point, Drop will send one of the following messages:
### Error event: `error/{task id}/{error title}/{error body}`
This means something has gone wrong with the task, and you should show or handle the error.
If "error title" is "Unknown task", your task ID was invalid, or you do not have the necessary ACLs to access the task.
This is different from an error generated from a task. This error is from Drop itself, not the task.
### Disconnect event: `disconnect/{task id}`
The task has ended, and you'll no longer recieve updates
### Task message: `{ ... JSON object ... }`
If the message isn't one of the two above ones, it'll be a stringified JSON object that represents a task message:
```json
{
"id": "...",
"name": "My Task",
"success": false,
"progress": 34,
"error": null,
"log": [
"... JSON object ...",
"... JSON object ...",
"... more JSON objects ...",
"... yet another JSON object ..."
],
"reset": false
};
```
### Task message properties
Here's what they do:
<Properties>
<Property name="id" type="string">
Task ID of this message
</Property>
<Property name="name" type="string">
User-friendly name of this task.
</Property>
<Property name="success" type="string">
If `true`, this task has completed without error.
</Property>
<Property name="error" type="object">
If not `null` or `undefined`, it will be an object:
```json
{
"title": "My Error",
"description": "Something has gone terribly wrong."
}
```
This means the task has errored out with the above error.
</Property>
<Property name="progress" type="number">
A number between 0-100 that represents the progress. Not guaranteed to be between 0-100, but we spit out warnings if it is.
</Property>
<Property name="log" type="string[]">
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.
Each log message is a JSON stringified object:
```json
{
"message": "my log line",
"level": "info",
"timestamp": "2025-09-23T06:37:19.047Z"
}
```
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:
| Number | String |
| ------ | ------ |
| 100 | silent |
| 60 | fatal |
| 50 | error |
| 40 | warn |
| 30 | info |
| 20 | debug |
| 10 | trace |
| 0 | off |
This also serves as a list of all possible `level` values*.*
</Property>
<Property name="reset" type="boolean">
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.
</Property>
</Properties>
---
## Fetch all tasks {{ tag: 'GET', label: '/api/v1/admin/task', apilevel: "system", acl: "task:read" }}
<Row>
<Col>
Fetches all tasks running, recently run, and scheduled for this instance.
<Note>
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}`.
</Note>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="GET" label="/api/v1/admin/task">
```bash {{ title: 'cURL' }}
curl -G http://localhost:3000/api/v1/admin/task \
-H "Authorization: Bearer {token}"
```
```js
const response = await fetch("http://localhost:3000/api/v1/admin/task", {
headers: {
Authorization: "Bearer {token}"
},
});
const { runningTasks, historicalTasks, dailyTasks, weeklyTasks } = await response.blob();
```
</CodeGroup>
```json {{ title: 'Response' }}
{
"runningTasks": [],
"historicalTasks": [
{
"id": "cleanup:invitations:2025-08-23T08:27:15.156Z",
"taskGroup": "cleanup:invitations",
"name": "Cleanup Invitations",
"started": "2025-08-23T08:27:15.156Z",
"ended": "2025-08-23T08:27:15.258Z",
"success": true,
"error": null,
"progress": 100,
"log": [
"{\"level\":\"info\",\"time\":\"2025-08-23T08:27:15.257Z\",\"msg\":\"Cleaning invitations\"}",
"{\"level\":\"info\",\"time\":\"2025-08-23T08:27:15.258Z\",\"msg\":\"Done\"}"
],
"acls": [
"system:maintenance:read"
]
},
{
"id": "cleanup:sessions:2025-08-23T01:02:47.015Z",
"taskGroup": "cleanup:sessions",
"name": "Cleanup Sessions",
"started": "2025-08-23T01:02:47.016Z",
"ended": "2025-08-23T01:02:47.132Z",
"success": true,
"error": null,
"progress": 100,
"log": [
"{\"level\":\"info\",\"time\":\"2025-08-23T01:02:47.116Z\",\"msg\":\"Cleaning up sessions\"}",
"{\"level\":\"info\",\"time\":\"2025-08-23T01:02:47.132Z\",\"msg\":\"Done\"}"
],
"acls": [
"system:maintenance:read"
]
},
],
"dailyTasks": [
"cleanup:invitations",
"cleanup:sessions",
"check:update"
],
"weeklyTasks": [
"cleanup:objects"
]
}
```
</Col>
</Row>
---
## Execute scheduled task {{ tag: 'POST', label: '/api/v1/admin/task', apilevel: "system", acl: "task:start" }}
<Row>
<Col>
This endpoint invokes a scheduled task by the task group name (see above, `dailyTasks` & `weeklyTasks`), and returns the task ID.
Despite not needing the task's ACL to start it, you will need the task's ACL to read it.
### Request body
<Properties>
<Property name="taskGroup" type="string">
Name of the task group to start.
</Property>
</Properties>
</Col>
<Col sticky>
<CodeGroup title="Request" tag="POST" label="/api/v1/admin/task">
```bash {{ title: 'cURL' }}
curl -X POST http://localhost:3000/api/v1/admin/task \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d "{ ... }"
```
```js
const response = await fetch("http://localhost:3000/api/v1/admin/task", {
headers: {
Authorization: "Bearer {token}"
},
method: "POST",
body: {
taskGroup: "..."
}
});
```
</CodeGroup>
```json {{ title: 'Response' }}
{
"id": "..."
}
```
</Col>
</Row>
---
## Scheduled tasks
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.
| Task Group | Task Name | Description |
| --------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `debug` | Debug Task | May not be implemented; usually removed for release and only added when needing to debug tasks. |
| `cleanup:invitations` | Cleanup Invitations | Deletes expired invitations from database to save space. Invitations check themselves regardless, this just cleans out old invitations. |
| `cleanup:objects` | Cleanup Objects | Deletes unreferenced objects from the object backend to save space. |
| `cleanup:sessions` | Cleanup Sessions | Cleans up expired sessions from the session handler. |
| `check:update` | Check for Update | Checks if there is an update for Drop available, and if so, send a notification to admins. |

View File

@@ -67,7 +67,6 @@ function NavLink({
? 'text-yellow-600/90 dark:text-yellow-400/70'
: 'text-zinc-400 dark:text-zinc-500'
return (
<CloseButton
as={Link}
@@ -270,6 +269,7 @@ export const navigation: Array<NavGroup> = [
links: [
{ title: 'Users', href: '/web/users' },
{ title: 'Objects', href: '/web/objects' },
{ title: 'Tasks', href: '/web/tasks' },
],
},
]

View File

@@ -10,10 +10,10 @@ import Link from 'next/link'
import { GridPattern } from '@/components/GridPattern'
import { Heading } from '@/components/Heading'
import { EnvelopeIcon } from '@/components/icons/EnvelopeIcon'
import { UserIcon } from '@/components/icons/UserIcon'
import { UsersIcon } from '@/components/icons/UsersIcon'
import { DocumentIcon } from '@/components/icons/DocumentIcon'
import { ShapesIcon } from '@/components/icons/ShapesIcon'
interface Resource {
href: string
@@ -56,11 +56,11 @@ const resources: Array<Resource> = [
},
},
{
href: '/messages',
name: 'Messages',
href: '/web/tasks',
name: 'Tasks',
description:
'Learn about the message model and how to create, retrieve, update, delete, and list messages.',
icon: EnvelopeIcon,
'Learn about Drop\' tasks system, and how to connect to and listen to them.',
icon: ShapesIcon,
pattern: {
y: 32,
squares: [
@@ -113,7 +113,7 @@ function ResourcePattern({
/>
</div>
<motion.div
className="absolute inset-0 rounded-2xl bg-linear-to-r from-blue-600/10 to-blue-400/10 opacity-0 transition duration-300 group-hover:opacity-100 dark:from-[#202D2E] dark:to-[#303428]"
className="absolute inset-0 rounded-2xl bg-linear-to-r from-blue-600/10 to-blue-400/10 opacity-0 transition duration-300 group-hover:opacity-100 dark:from-blue-400/20 dark:to-blue-600/20"
style={style}
/>
<motion.div