Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions examples/01-hello-world/hello-job.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* eslint-disable no-console */

import { Job } from "sidequest";

export class HelloJob extends Job {
run(name: string) {
const msg = `hello ${name}`;
console.log(msg);
return msg;
}
}
6 changes: 6 additions & 0 deletions examples/01-hello-world/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Sidequest } from "sidequest";
import { HelloJob } from "./hello-job.js";

await Sidequest.start();

await Sidequest.build(HelloJob).enqueue("John Doe");
7 changes: 7 additions & 0 deletions examples/02-recurring-job/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Sidequest } from "sidequest";
import { SampleJob } from "./sample-job.js";

await Sidequest.start();

// every 10 minutes
await Sidequest.build(SampleJob).schedule("*/10 * * * * *");
11 changes: 11 additions & 0 deletions examples/02-recurring-job/sample-job.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* eslint-disable no-console */

import { Job } from "sidequest";

export class SampleJob extends Job {
run() {
const msg = "sample job";
console.log(msg);
return msg;
}
}
6 changes: 6 additions & 0 deletions examples/03-snooze-job/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Sidequest } from "sidequest";
import { SnoozeJob } from "./snooze-job.js";

await Sidequest.start();

await Sidequest.build(SnoozeJob).enqueue();
8 changes: 8 additions & 0 deletions examples/03-snooze-job/snooze-job.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Job } from "sidequest";

export class SnoozeJob extends Job {
run() {
// Pauses the job for 10 seconds before retrying — can be used to wait for external conditions.
return this.snooze(10_000);
}
}
20 changes: 20 additions & 0 deletions examples/04-enqueue-job-from-api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/* eslint-disable no-console */

import { Sidequest } from "sidequest";

import express from "express";
import { SendEmailJob } from "./send-email-job.js";

const app = express();

app.get("/send-email", (req, res) => {
const email = req.query.email ?? "[email protected]";
void Sidequest.build(SendEmailJob).enqueue(email as string);
res.send(204);
});

await Sidequest.start();

app.listen(3000, () => {
console.log("call http://localhost:3000/[email protected]");
});
11 changes: 11 additions & 0 deletions examples/04-enqueue-job-from-api/send-email-job.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* eslint-disable no-console */

import { Job } from "sidequest";

export class SendEmailJob extends Job {
run(email: string) {
const msg = `sending email to ${email}`;
console.log(msg);
return msg;
}
}
28 changes: 28 additions & 0 deletions examples/05-web-scrapping/count-word-job.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* eslint-disable no-console */

import { load } from "cheerio";
import { Job } from "sidequest";

export class CountWordJob extends Job {
async run(url: string, word: string) {
const response = await fetch(url);
const html = await response.text();

const $ = load(html);
const text = $("body").text();

const regex = new RegExp(`\\b${word}\\b`, "gi");
const matches = text.match(regex);
const count = matches ? matches.length : 0;

console.log(`The word "${word}" appears ${count} times on the page ${url}`);

// Return the result as an object
// Will be available in the result of the job
return {
word,
count,
url,
};
}
}
6 changes: 6 additions & 0 deletions examples/05-web-scrapping/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Sidequest } from "sidequest";
import { CountWordJob } from "./count-word-job.js";

await Sidequest.start();

await Sidequest.build(CountWordJob).enqueue("https://en.wikipedia.org/wiki/Node.js", "package");
19 changes: 19 additions & 0 deletions examples/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "examples",
"version": "1.0.0",
"type": "module",
"private": true,
"scripts": {
"build": "tsc"
},
"dependencies": {
"@sidequest/sqlite-backend": "workspace:*",
"cheerio": "^1.1.2",
"express": "^5.1.0",
"sidequest": "workspace:*"
},
"devDependencies": {
"@types/express": "^5",
"typescript": "^5.8.3"
}
}
20 changes: 20 additions & 0 deletions examples/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2022"],
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"outDir": "dist",
"rootDir": ".",
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["."],
"exclude": ["dist", "node_modules"]
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
},
"workspaces": [
"packages/*",
"packages/backends/*"
"packages/backends/*",
"examples"
],
"scripts": {
"build": "cross-env NODE_ENV=production turbo run build",
"build:examples": "cross-env NODE_ENV=production turbo run build --filter=examples",
"test": "yarn vitest --exclude packages/backends",
"test:ci": "turbo run test:ci --filter=!'@sidequest/*-backend'",
"test:debug": "yarn vitest --test-timeout=0 --exclude packages/backends",
Expand Down
192 changes: 178 additions & 14 deletions packages/docs/examples.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,193 @@
---
outline: deep
title: Examples
description: Examples for Sidequest.js
description: Practical examples demonstrating Sidequest.js features and common use cases
---

# Examples

## Express.js Integration
This page showcases practical examples that demonstrate how to use Sidequest.js in real-world scenarios. Each example includes complete, runnable code that you can use as a starting point for your own applications.

```typescript
import express from "express";
import { Sidequest } from "sidequest";
import { EmailJob } from "./jobs/EmailJob.js";
## 1. Hello World

const app = express();
The simplest possible Sidequest example - creating and running a basic job.

app.post("/send-email", async (req, res) => {
const { to, subject, body } = req.body;
**What it demonstrates:**

const job = await Sidequest.build(EmailJob).queue("emails").enqueue(to, subject, body);
- Creating a basic job class
- Starting Sidequest with default configuration
- Enqueueing a job with parameters

res.json({ jobId: job.id, message: "Email queued successfully" });
});
### Job Class

await Sidequest.start();
<<< @/../../examples/01-hello-world/hello-job.ts

app.listen(3000);
### Main Application

<<< @/../../examples/01-hello-world/index.ts

**Key concepts:**

- All jobs extend the `Job` base class
- The `run()` method contains your job logic
- Jobs can accept parameters and return values
- Sidequest starts with sensible defaults (SQLite backend, dashboard on port 8678)

## 2. Recurring Jobs

Schedule jobs to run automatically at specified intervals using cron expressions.

**What it demonstrates:**

- Using the `.schedule()` method instead of `.enqueue()`
- Cron expression syntax for job scheduling
- Setting up recurring background tasks

### Job Class

<<< @/../../examples/02-recurring-job/sample-job.ts

### Main Application

<<< @/../../examples/02-recurring-job/index.ts

**Key concepts:**

- Use `.schedule()` for recurring jobs instead of `.enqueue()`
- Cron expressions control when jobs run (this example runs every 10 seconds)
- Scheduled jobs are in-memory only and need to be re-registered on restart
- Scheduled jobs enqueue other jobs (those are persisted)
- Perfect for maintenance tasks, data processing, or periodic notifications

## 3. Job Snoozing

Implement jobs that can pause themselves and resume later, useful for waiting on external conditions.

**What it demonstrates:**

- Using `this.snooze()` to pause job execution
- Handling jobs that need to wait for external conditions
- Job lifecycle management

### Job Class

<<< @/../../examples/03-snooze-job/snooze-job.ts

### Main Application

<<< @/../../examples/03-snooze-job/index.ts

**Key concepts:**

- `this.snooze(milliseconds)` pauses a job and reschedules it for later
- Useful for rate limiting, waiting for external APIs, or implementing backoff strategies
- The job will be retried after the specified delay
- Snoozing doesn't count against the job's retry attempts

## 4. API-Triggered Jobs

Integrate Sidequest with a web API to enqueue jobs from HTTP requests.

**What it demonstrates:**

- Enqueueing jobs from within an Express.js application
- Asynchronous job processing triggered by user actions
- Separating web request handling from background processing

### Job Class

<<< @/../../examples/04-enqueue-job-from-api/send-email-job.ts

### Express Application

<<< @/../../examples/04-enqueue-job-from-api/index.ts

**Key concepts:**

- Jobs are enqueued asynchronously and don't block the HTTP response
- Use `void` when you don't need to wait for job completion
- This pattern is perfect for time-consuming tasks like sending emails, processing images, or generating reports
- The API responds immediately while work happens in the background

**Try it out:**

```bash
# Start the server
npm run start

# Trigger a job
curl "http://localhost:3000/[email protected]"
```

## 5. Web Scraping

A more complex example that demonstrates real-world job processing with external HTTP requests and data processing.

**What it demonstrates:**

- Jobs that make external HTTP requests
- Processing and parsing HTML data
- Returning structured results from jobs
- Using external dependencies (cheerio for HTML parsing)

### Job Class

<<< @/../../examples/05-web-scrapping/count-word-job.ts

### Main Application

<<< @/../../examples/05-web-scrapping/index.ts

**Key concepts:**

- Jobs can make external HTTP requests and process the responses
- Use `async/await` for asynchronous operations within jobs
- Return structured data that will be stored with the job results
- External libraries like `cheerio` can be used for data processing
- Perfect for data collection, content analysis, or API integration tasks
- If the job fails (e.g., rate limiting), it will be retried based on your configuration

## Running the Examples

All examples are located in the [`/examples` directory](https://github.com/sidequestjs/sidequest/tree/develop/examples) of the Sidequest repository. To run any example, navigate to Sidequest's root directory and run:

```bash
yarn install
```

Then build the examples:

```bash
yarn build:examples
```

Then run any example with:

```bash
node examples/dist/01-hello-world/index.js
```

### Viewing the Dashboard

All examples start the Sidequest dashboard automatically. You can view job execution in real-time:

```text
http://localhost:8678
```

The dashboard shows:

- Job execution status and history
- Queue management and statistics
- Real-time job processing metrics
- Job details including arguments and results

## Next Steps

After exploring these examples:

1. **Learn about [Job Classes](/jobs/index)** - Understand job lifecycle and advanced features
2. **Explore [Queue Management](/queues/index)** - Configure queues for different priorities and concurrency
3. **Read the [Configuration Guide](/engine/configuration)** - Customize Sidequest for your environment
4. **Check out the [Dashboard](/dashboard)** - Monitor and manage your jobs
5. **Review [Best Practices](/engine/graceful-shutdown)** - Production deployment considerations
Loading
Loading