On-Premise Tasks is a managed execution service for task delivery or distribution needs. Technically, a task is an object that represents a single-use execution resource. You can request tasks to On-Premise Tasks, which will then be executed at a future time. On-Premise Tasks will execute it and send it to the specified target URL
- HTTP request
- Retry mechanism
- Scheduling
Make sure you have bun and rust installed, then run:
./init.sh
To start the development server, run:
bun run dev
To start the test server, run:
bun run test
# Or test specifically the file name
bun test <FILENAME>
To start the single file executable, run:
# Compile
bun run bin
# Run
./tasks
To start docker or podman during development, run:
# For docker
docker compose -p <STACK_NAME> --env-file <ENV_FILE> up -d --build
# For podman
podman compose -p <STACK_NAME> --file docker-podman-compose.yaml --env-file <ENV_FILE> up -d --build
# Cleanup
docker/podman compose -p <STACK_NAME> down
Why Rocky Linux? By default, Rocky Linux includes curl with the latest version that supports DNS features. However, it's also recommended to consider using other minimalist Docker images, such as distroless, with curl included. Developer strive to keep the image minimalist for production needs.
You can use absolute path or current working path, for example:
# Absolute path
/tmp/tasks/db/tasks.db
# Current working path
./db/tasks.db
- ✅
GET /subscribers/:name
- ✅
DELETE /subscribers/:name
- ✅
POST /subscribers/register
- ✅
GET /queues
- ✅
GET /queues/:id
- ❌
PATCH /queues/:id
- ✅
DELETE /queues/:id
- ❌
GET /queues/:id/config
- ✅
PATCH /queues/:id/pause
- ✅
PATCH /queues/:id/resume
- ✅
PATCH /queues/:id/unsubscribe
- ✅
POST /queues/register
interface TaskSubscriberRequest {
httpRequest: TasksHttp;
config?: TasksConfig;
}
type PlainTextData = string;
type MultipartFormData = {
name: string;
value: string;
}
type ApplicationJsonData = {
[key: string]: any;
}
interface TasksHttp {
url: string;
method?: "GET" | "POST" | "DELETE" | "PATCH" | "PUT";
data?: PlainTextData | Array<MultipartFormData> | ApplicationJsonData;
query?: {
[key: string]: string;
};
cookie?: Array<{
name: string;
value: string;
}>;
headers?: {
[key: string]: string;
};
authBasic?: {
user: string;
password: string;
};
}
interface TasksConfig {
executionDelay?: number; // Default 1ms, min: 0
executeAt?: number; // Default 0
retry?: number; // Default 0, min: 0, max: 4096
retryAt?: number; // Default 0
retryInterval?: number; // Default 0, min: 0, max: 604800000ms
retryStatusCode?: Array<number>; // Default []
retryExponential?: boolean; // Default true
timeout?: number; // Default 30000ms, min: 1000ms, max: 3600000ms
timeoutAt?: number; // Default 0
//
// The configuration below refers to the curl options (not all options are supported)
// Visit https://curl.se/docs/manpage.html for more information
//
dnsServer?: Array<string> | null;
dohInsecure?: boolean;
dohUrl?: string | null;
httpVersion?: "0.9" | "1.0" | "1.1" | "2";
insecure?: boolean;
refererUrl?: string | "AUTO" | null;
redirectAttempts?: number;
keepAliveDuration?: number;
resolve?: Array<{
host: string;
port: number;
address: Array<string>;
}> | null;
proxy: {
protocol: "http" | "https";
host: string;
port?: number;
} | null;
proxyAuthBasic: {
user: string;
password: string;
} | null;
proxyHeaders: {
[key: string]: string;
} | null;
proxyHttpVersion: "1.0" | "1.1";
proxyInsecure: boolean;
}
An example of requesting a Task
{
"httpRequest": {
"url": "https://dummyjson.com/todos/1",
"method": "GET"
},
"config": {
"executionDelay": 86400000,
"retry": 5,
"retryInterval": 3600000,
"retryExponential": false
}
}
curl -X POST \
-H "authorization: Bearer <KEY>" \
-H "content-type: application/json" \
-H "x-tasks-subscriber-id: <ID>" \
-d @req.json \
http://localhost:3200/queues/register
The example above, the task will be executed after waiting for 1 day. If the task receives a 4xx-5xx error response, it will be run again 5 times with a 1-hour interval between each execution. If retryExponential = true
, the interval between each execution will increase
retryInterval = 3600000ms
Retry-1: 3600000 * 1 = 3600000ms
Retry-2: 3600000 * 2 = 7200000ms
Retry-3: 3600000 * 3 = 10800000ms
And so on...
Additionally, you can make a specific request by using executeAt
{
"httpRequest": {
"url": "https://dummyjson.com/todos/1",
"method": "GET"
},
"config": {
"executeAt": 2619277200000
}
}
curl -X POST \
-H "authorization: Bearer <KEY>" \
-H "content-type: application/json" \
-H "x-tasks-subscriber-id: <ID>" \
-d @req.json \
http://localhost:3200/queues/register
Please note that properties ending with "At"
are in UNIX time format:
executeAt
retryAt
timeoutAt
Attention:
retryAt
is the same asretry = 1
with a specific timetimeoutAt
will be executed only once. If the task has been retried several times, then it will continue usingtimeout
.
To find out milliseconds in various programming languages, you can visit https://currentmillis.com and remember to set the environment variable TZ=UTC
on the Tasks Server.
There are two backup methods:
- Local. The local method copies the database file, then moves it to another directory. This method is active by default
- Google Cloud Storage. The Google Cloud Storage method uploads database files to a Google Cloud Storage. This step is highly recommended.
You can set it via env variable
type SqliteBackupMethod = "LOCAL" | "GOOGLE_CLOUD_STORAGE"
BACKUP_METHOD_SQLITE="LOCAL"
You can also set the backup interval using the cron format
# Default: Every day at midnight
BACKUP_CRON_PATTERN_SQLITE="0 0 * * *"
- Create a service account and do not grant any access, just create!
- Create a new key (select the JSON format)
- Go to Google Cloud Storage, create a bucket
- Click the three-dot icon in the corner of the bucket table to perform more actions, then click edit access
- Click add principal
- Enter the service account email and assign roles:
- Storage Object User
- Storage Object Viewer
- Click save