UNPKG

blazerjob

Version:

TypeScript library for scheduling, executing, and managing asynchronous tasks (custom, HTTP, Cosmos) with a SQLite backend.

563 lines (437 loc) 17.8 kB
# BlazerJob – Task Scheduler Library **BlazerJob** is a lightweight, SQLite-backed task scheduler for Node.js and TypeScript applications. Use it as a library in your code to schedule, execute, and manage asynchronous tasks. # Supported Connectors BlazerJob currently supports only the following connectors for actual execution: | Connector Type | Status | Description | |---------------|---------------|------------------------------------------------------------------| | `cosmos` | Supported | Send tokens, query balances/transactions, batch Cosmos queries | | `http` | Supported | Generic HTTP requests (GET, POST, etc.) | | `shell` | Not supported | Present in types, but not executed (ignored/logged only) | | `onchain` | Not supported | Present in types, but not executed (ignored/logged only) | | `solana` | Not supported | Present in types, but not executed (ignored/logged only) | | `email` | Not supported | Present in types, but not executed (ignored/logged only) | | `fintech` | Not supported | Present in types, but not executed (ignored/logged only) | > Only tasks of type `cosmos` and `http` are actually executed by BlazerJob. All other types are reserved for future extensions or compatibility, but are currently ignored or simply logged by the server. ## 1. Custom Tasks (Arbitrary JavaScript/TypeScript) BlazerJob can schedule and execute any custom asynchronous JavaScript/TypeScript function. This is the most flexible way to use the scheduler, and is ideal for business logic, scripts, or workflows that don't fit a predefined connector. ### Example: Custom Task ```typescript const jobs = new BlazeJob({ dbPath: './tasks.db' }); jobs.schedule(async () => { // Your custom logic here console.log('Hello from a custom task!'); // You can use any Node.js/TypeScript code }, { runAt: new Date(), interval: 5000, // optional: repeat every 5 seconds maxRuns: 3, // optional: stop after 3 executions onEnd: (stats) => { console.log('Task finished. Stats:', stats); } }); jobs.start(); ``` --- ## 2. HTTP Tasks (API Calls) BlazerJob natively supports HTTP tasks for scheduling API calls (GET, POST, etc.). ### Example: HTTP POST Request ```typescript jobs.schedule(async () => {}, { runAt: new Date(), type: 'http', config: JSON.stringify({ url: 'https://httpbin.org/post', method: 'POST', headers: { 'Content-Type': 'application/json' }, body: { hello: 'world' } }) }); ``` ### Example: HTTP GET Request ```typescript jobs.schedule(async () => {}, { runAt: new Date(), type: 'http', config: JSON.stringify({ url: 'https://api.coindesk.com/v1/bpi/currentprice.json', method: 'GET' }) }); ``` --- ## 3. Cosmos Tasks (Blockchain) BlazerJob supports Cosmos blockchain tasks for sending tokens, querying balances, and more. - **Accepted type**: `cosmos` - **Features**: - Token transfer (sendTokens) - Balance queries, transactions (tx), and custom queries - Batch Cosmos queries via `scheduleManyCosmosQueries` ### Example: Cosmos Balance Query ```typescript jobs.schedule(async () => {}, { runAt: new Date(), type: 'cosmos', config: JSON.stringify({ queryType: 'balance', queryParams: { address: 'cosmos1...' } }) }); ``` ### Example: Send Cosmos Tokens ```typescript jobs.schedule(async () => {}, { runAt: new Date(), type: 'cosmos', config: JSON.stringify({ to: 'cosmos1...', amount: '100000', denom: 'uatom', mnemonic: process.env.COSMOS_MNEMONIC, chainId: 'cosmoshub-4', rpcUrl: process.env.COSMOS_RPC_URL }) }); ``` ## Required Environment Variables - `COSMOS_MNEMONIC` Cosmos mnemonic - `COSMOS_RPC_URL` Cosmos RPC endpoint ## Other Task Types Any type other than `cosmos` (e.g., `shell`, `onchain`, `solana`, `email`, `fintech`, `http`) will be ignored and simply logged. To extend, you will need to reactivate or develop the corresponding connector. ## CLI BlazerJob provides a CLI to easily manage your scheduled tasks: ```bash # Show help npx ts-node src/bin/cli.ts help # Schedule a task (e.g., shell) npx ts-node src/bin/cli.ts schedule --type shell --cmd "echo hello" --runAt "2025-01-01T00:00:00Z" # List tasks (default blazerjob.db) npx ts-node src/bin/cli.ts list # List tasks from ALL .db files in the current directory ts-node src/bin/cli.ts list-all # Delete a task npx ts-node src/bin/cli.ts delete 123 ``` ### Available Commands #### `list-all` Displays tasks from all `.db` files in the current directory, with separate sections for each database. **Example Output:** ``` === Database: blazerjob.db === ┌─────────┬────┬─────────┬────────────────────────────┬──────────┬─────────────────────────────┐ (index) id type runAt status config ├─────────┼────┼─────────┼────────────────────────────┼──────────┼─────────────────────────────┤ 0 1 'cosmos' '2025-05-05T21:24:13.727Z' 'failed' '{"cmd":"echo test"}' └─────────┴────┴─────────┴────────────────────────────┴──────────┴─────────────────────────────┘ === Database: tasks_cosmos_query.db === ┌─────────┬────┬──────────┬────────────────────────────┬──────────┬─────────────────────────────────────┐ (index) id type runAt status config ├─────────┼────┼──────────┼────────────────────────────┼──────────┼─────────────────────────────────────┤ 0 42 'cosmos' '2025-05-06T02:21:28.275Z' 'failed' '{"queryType":"balance",...}' └─────────┴────┴──────────┴────────────────────────────┴──────────┴─────────────────────────────────────┘ ``` #### `list` Shows tasks only from the default database (`blazerjob.db`). #### `schedule` Schedules a new task. Available options: - `--type`: Task type (`cosmos`) - `--cmd`: Command to execute (for cosmos tasks) - `--runAt`: Execution time (default: now) - `--interval`: Repeat interval in ms (optional) - `--priority`: Task priority (optional) - `--retriesLeft`: Number of retry attempts (optional) - `--webhookUrl`: Webhook URL for notifications (optional) #### `delete <id>` Deletes a task by its ID. --- ## Installation ```bash npm install blazerjob ``` --- ## Import ```typescript import { BlazeJob } from 'blazerjob'; ``` --- ## Environment Variables & Secrets BlazerJob uses [dotenv](https://github.com/motdotla/dotenv) to securely load secrets (like private keys and RPC URLs) from a `.env` file. 1. Copy `.env.example` to `.env` and fill in your secrets: ```bash cp .env.example .env ``` Example `.env`: ``` COSMOS_MNEMONIC=0xYOUR_COSMOS_MNEMONIC COSMOS_RPC_URL=https://mainnet.infura.io/v3/YOUR_INFURA_KEY ``` - **Never commit your real `.env` to version control!** - You can omit `privateKey` and `rpcUrl` from the task config to use values from the environment. - This pattern can be used for other secrets (API keys, fintech credentials, etc.) in custom handlers. --- ## API Reference ### `new BlazeJob(options: { dbPath: string })` - **dbPath**: Path to the SQLite database file where tasks are stored. ### schedule(taskFn: () => Promise<void>, opts: { ... }): number - **taskFn**: Asynchronous function to execute (your JS/TS code). - **opts**: - `runAt`: Date or ISO string for when to run the task. - `interval?`: (optional) Number of milliseconds between executions (for recurring tasks). - `priority?`: (optional) Higher priority tasks run first. - `retriesLeft?`: (optional) Number of retry attempts if the task fails. - `type`: Task type (e.g. `'cosmos'`). - `config?`: (optional) Additional configuration for the task, see [TaskConfig](#taskconfig-interface) below. - `webhookUrl?`: (optional) If set, BlazerJob will POST a JSON payload to this URL on task success, failure, or retry. Returns the ID of the created task. ### start(): Promise<void> - Starts the scheduler loop (automatically executes due tasks). ### stop(): void - Stops the scheduler loop (does not close the database). --- ## Arrêt automatique du process (option autoExit) For testing or scripting purposes, you can configure BlazeJob to automatically exit the process as soon as all periodic tasks (with `maxRuns` or `maxDurationMs`) are completed: ```typescript const jobs = new BlazeJob({ dbPath: './test.db', autoExit: true }); jobs.schedule(async () => {}, { runAt: new Date(), interval: 2000, maxRuns: 3, onEnd: (stats) => { console.log('Summary:', stats); } }); jobs.start(); // The process will automatically exit after the last periodic task is finished. ``` - If `autoExit` is not enabled, the process will continue running as usual. - You can also use the global `onAllTasksEnded` callback to perform actions at the end, without stopping the process: ```typescript jobs.onAllTasksEnded(() => { console.log('All periodic tasks are done.'); }); ``` ## Bonnes pratiques - **Enable `autoExit` only for scripts or tests.** - **In production/server, leave `autoExit` as `false` (the default) to prevent unexpected process termination.** --- ## TaskConfig Interface BlazerJob supports the following task types and config structures: ```typescript type TaskType = 'cosmos'; interface CosmosTaskConfig { queryType: 'balance' | 'tx' | 'custom'; queryParams?: Record<string, string>; to?: string; amount?: string; denom?: string; mnemonic?: string; chainId?: string; rpcUrl?: string; } ``` --- ## Webhook Notifications If you set `webhookUrl` when scheduling a task, BlazerJob will POST a JSON payload to that URL on task completion (success, failure, or retry). ### Example Payload (Success) ```json { "taskId": 42, "status": "done", "executedAt": "2025-05-05T23:50:00Z", "result": "success", "output": null, "error": null } ``` ### Example Payload (Failure) ```json { "taskId": 42, "status": "failed", "executedAt": "2025-05-05T23:51:00Z", "result": "error", "output": null, "error": "Command failed: ..." } ``` ### Example Payload (Retry) ```json { "taskId": 42, "status": "pending", "executedAt": "2025-05-05T23:52:00Z", "result": "retry", "output": null, "error": "Temporary error message" } ``` --- ## Exemple : requête simple Cosmos (balance ou tx) Here’s how to use BlazerJob to execute a simple query on Cosmos (for example, to get the balance of an address or transaction info): ### 1. Query balance (solde) ```typescript import { BlazeJob } from 'blazerjob'; const jobs = new BlazeJob({ dbPath: './tasks.db' }); jobs.schedule(async () => {}, { runAt: new Date(), type: 'cosmos', config: JSON.stringify({ queryType: 'balance', queryParams: { address: 'cosmos1...' }, // rpcUrl peut venir de .env ou être spécifié ici }) }); jobs.start(); ``` ### 2. Query transaction (tx) ```typescript import { BlazeJob } from 'blazerjob'; const jobs = new BlazeJob({ dbPath: './tasks.db' }); jobs.schedule(async () => {}, { runAt: new Date(), type: 'cosmos', config: JSON.stringify({ queryType: 'tx', queryParams: { hash: '0x...' }, // rpcUrl peut venir de .env ou être spécifié ici }) }); jobs.start(); ``` - Results are logged on the server side (console). - For a custom query, use `queryType: 'custom'` and adapt `queryParams` as needed. --- ## Example: Scheduled HTTP request (http connector) BlazerJob now lets you schedule an HTTP API request (using fetch): ### Example: simple POST request ```typescript import { BlazeJob } from 'blazerjob'; const jobs = new BlazeJob({ dbPath: './tasks.db' }); jobs.schedule(async () => {}, { runAt: new Date(), type: 'http', config: JSON.stringify({ url: 'https://httpbin.org/post', method: 'POST', headers: { 'Content-Type': 'application/json' }, body: { hello: 'world' } }) }); jobs.start(); ``` ### Exemple : requête GET ```typescript jobs.schedule(async () => {}, { runAt: new Date(), type: 'http', config: JSON.stringify({ url: 'https://api.coindesk.com/v1/bpi/currentprice.json', method: 'GET' }) }); ``` ### Exemple : requête GET toutes les 10 secondes avec log de la réponse ```typescript import { BlazeJob } from 'blazerjob'; const jobs = new BlazeJob({ dbPath: './tasks.db' }); jobs.schedule(async () => {}, { runAt: new Date(), interval: 10000, // toutes les 10 secondes type: 'http', config: JSON.stringify({ url: 'https://api.coindesk.com/v1/bpi/currentprice.json', method: 'GET' }) }); jobs.start(); ``` > Pour logguer la réponse côté serveur, modifie la fonction dans le code source : > > ```typescript > taskFn = async () => { > const res = await fetch(cfg.url, { > method: cfg.method ?? 'POST', > headers: cfg.headers, > body: cfg.body ? JSON.stringify(cfg.body) : undefined > }); > const text = await res.text(); > console.log('[HTTP][response]', text); > }; > ``` --- ## Cosmos Module: Centralized Logic BlazerJob centralizes all Cosmos blockchain logic in the `src/cosmos/` module. This module exposes helpers for scheduling, querying, and sending tokens on Cosmos chains (CosmJS-compatible). ### Features - **Batch scheduling**: Schedule hundreds of Cosmos queries or transactions in one call. - **Unified helpers**: Query balances, transactions, and send tokens using a simple API. - **Environment support**: Cosmos mnemonic and RPC URL can be set in `.env` or provided per task. - **Error handling**: Centralized error helpers for Cosmos-specific issues (rate limits, etc). - **TypeScript-first**: All helpers are typed for safe use. ### Example: Batch Cosmos Queries ```typescript import { BlazeJob } from 'blazerjob'; import { scheduleManyCosmosQueries } from './src/cosmos'; const job = new BlazeJob({ dbPath: './tasks.db' }); await scheduleManyCosmosQueries(job, { addresses: [ 'cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh', 'cosmos1c9ye9j3p4e9w8f7j2k7l6k8e8f7g9h5d3j8k7h', ], count: 100, queryType: 'balance', intervalMs: 100, }); job.start(); ``` ### Example: Query Cosmos Balance or Transaction ```typescript import { getBalance, getTx } from './src/cosmos'; const balances = await getBalance(process.env.COSMOS_RPC_URL, 'cosmos1...'); const tx = await getTx(process.env.COSMOS_RPC_URL, '0x...'); ``` ### Example: Send Tokens on Cosmos ```typescript import { sendTokens } from './src/cosmos'; await sendTokens({ rpcUrl: process.env.COSMOS_RPC_URL, mnemonic: process.env.COSMOS_MNEMONIC, to: 'cosmos1destination...', amount: '100000', denom: 'uatom', chainId: 'cosmoshub-4', }); ``` ### Environment Variables - `COSMOS_MNEMONIC` Cosmos wallet mnemonic - `COSMOS_RPC_URL` Cosmos RPC endpoint See `.env.example` for details. --- ## Cosmos Helpers (API) BlazerJob exposes various Cosmos helpers in `src/cosmos/queries.ts`: - `getBalance(rpcUrl, address)`: Gets the balance of an address - `getTx(rpcUrl, hash)`: Retrieves a transaction by hash - `sendTokens({rpcUrl, mnemonic, to, amount, denom, ...})`: Sends ATOM or other tokens - `getLatestBlockHeight(rpcUrl)`: Gets the latest block height - `getBlockByHeight(rpcUrl, height)`: Gets block details by height - `getAccountInfo(rpcUrl, address)`: Gets account info (account number, sequence, ...) - `getAllBalances(rpcUrl, address)`: Gets all balances for an address - `getChainId(rpcUrl)`: Gets the chain ID - `getTransactionByHash(rpcUrl, hash)`: Alias for `getTx` - `searchTxs(rpcUrl, query)`: Searches transactions (by address, event, ...) - `broadcastTx(rpcUrl, txBytes)`: Broadcasts a signed transaction - `getDelegation(rpcUrl, delegator, validator)`: Gets specific staking delegation > Some advanced queries (validators, supply, node info) require a REST/LCD endpoint (not included in StargateClient, see cosmjs/launchpad/lcd or fetch). #### Advanced Usage Example ```typescript import { getBalance, getTx, sendTokens, getLatestBlockHeight, getBlockByHeight, getAccountInfo, getAllBalances, getChainId, getTransactionByHash, searchTxs, broadcastTx, getDelegation } from './src/cosmos'; const balances = await getAllBalances(process.env.COSMOS_RPC_URL, 'cosmos1...'); const block = await getBlockByHeight(process.env.COSMOS_RPC_URL, 1234567); const delegation = await getDelegation(process.env.COSMOS_RPC_URL, 'cosmos1delegator...', 'cosmosvaloper1validator...'); ``` --- ## License GNU