Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added nextjs 13 app router native support & docs improvements. #1141

Merged
merged 12 commits into from
Jun 20, 2023
38 changes: 31 additions & 7 deletions docs/docs/api/next.md → docs/docs/api/next.mdx
Original file line number Diff line number Diff line change
@@ -1,21 +1,44 @@
---
title: Next.js
---
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

```ts title="pages/api/someQueue.ts"
import { Queue } from "quirrel/next";
# Next.js

export default Queue(
"api/someQueue",
<Tabs>
<TabItem value="app" label="App Router">

```typescript title="app/api/queues/sample/route.ts"
import { Queue } from "quirrel/next-app";

export const sampleQueue = Queue(
"api/queues/sample",
async (job, meta) => {
// do something
}
);

export const POST = sampleQueue;
```

Creates a new Queue.
Make sure to export it from a [Route Handler](https://nextjs.org/docs/app/building-your-application/routing/router-handlers), otherwise it won't work.

</TabItem>
<TabItem value="page" label="Pages Router">

```typescript title="pages/api/queues/sample.ts"
import { Queue } from "quirrel/next-pages";

export default Queue("api/queues/sample", async (job, meta) => {
// do something
});
```

Creates a new Queue.
Make sure to export it from an [API Route](https://nextjs.org/docs/api-routes/introduction), otherwise it won't work.

</TabItem>
</Tabs>

#### Parameters

```ts
Expand All @@ -26,6 +49,7 @@ function Queue<T>(
): QueueInstance<T>
```


| Parameter | Usage |
| ------------------- | --------------------------------------------------------------- |
| `path` | The route that this queue is reachable at. |
Expand Down
79 changes: 0 additions & 79 deletions docs/docs/deploying.md

This file was deleted.

44 changes: 44 additions & 0 deletions docs/docs/deployment/connecting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: Connecting your Application
---

To deploy Quirrel, first set up your Quirrel server via [Docker](./docker), [Railway](./railway) or [Fly.io](./fly).

There are three main environment variables you need to specify in your deployment settings:

| Variable | Meaning | Where to get |
| --------------------------- | -------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `QUIRREL_TOKEN` | access token for the Quirrel server. | See "Acquire a token" section below |
| `QUIRREL_BASE_URL` | The base URL of your application's deployment. | You probably know this. Something like `my-application.com`. |
| `QUIRREL_ENCRYPTION_SECRET` | A 32-character-long secret used for end-to-end encryption of your jobs. | Can be generated using `openssl rand -hex 16` or [random.org](https://www.random.org/strings/?num=2&len=16&digits=on&upperalpha=on&loweralpha=on&unique=on&format=html&rnd=new). |
| `QUIRREL_API_URL` | The endpoint your Quirrel Server is running under, e.g. http://your-quirrel-api-address:9181 | |

After setting these variables, you can deploy your application and Quirrel should be working.
If it doesn't, feel free to [reach out](mailto:troubleshooting@quirrel.dev).

:::note Cron Jobs
If you're using [CronJobs()](/api/cronjob), make sure to run `quirrel ci` during the deploy process.
Make sure to have `QUIRREL_API_URL`, a `QUIRREL_TOKEN` and the `QUIRREL_BASE_URL` set when executing `quirrel ci`.

```json
"scripts": { "build": "npm run build && quirrel ci" }
```

:::

:::note VERCEL*URL
If you're on Vercel, you can connect `QUIRREL_BASE_URL` to your `VERCEL_URL`.
Only do this for preview environments, \_not for production*!
`QUIRREL_BASE_URL` is used to determine the deployment that your jobs should be executed on.
If you set it to `VERCEL_URL`, that means all jobs will be executed on the exact deployment that they were
created on, excluding them from future bugfixes.
To connect `QUIRREL_BASE_URL` to `VERCEL_URL`, set its value to `@VERCEL_URL` ([notice the @](https://github.com/quirrel-dev/quirrel/blob/d268f0555211afb202c3c3b12b460d14f0f0fb86/quirrel/src/client/config.ts#L12)).
:::

### Acquire a token

You can acquire an authentication token from your Quirrel Server by running this command:

`curl --user ignored:{PASSPHRASE} -X PUT {QUIRREL_SERVER_URL}/tokens/{NAME_OF_TOKEN}`

> The fields inside of `{}` are placeholders and should be replaced by you.
26 changes: 26 additions & 0 deletions docs/docs/deployment/docker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Docker

To deploy Quirrel using Docker, first set up a Redis instance with persistence turned on. Then follow these steps:

1. Pull the official Quirrel Docker image:

```bash
docker pull ghcr.io/quirrel-dev/quirrel:main
```

2. Define your environment variables in a `.env` file:

```env
REDIS_URL=your_redis_url
PASSPHRASES=your_passphrases
REDIS_TLS_CA_BASE64=your_base64_encoded_certificate # if applicable
REDIS_TLS_CA_FILE=your_certificate_file_path # if applicable
```

3. Run the Docker container, replace `<name_of_your_container>` with your preferred container name:

```bash
docker run --env-file .env -p 9181:9181 ghcr.io/quirrel-dev/quirrel:main
```

This will start a new Quirrel container and expose it on port 9181.
5 changes: 5 additions & 0 deletions docs/docs/deployment/fly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Fly.io

If you're planning to host your Quirrel instance on Fly.io, you can follow [Mokhtar Mial](https://twitter.com/m5r_m)'s tutorial:

[Self-Hosting Quirrel on Fly.io](https://dev.to/remixtape/self-hosting-quirrel-5af7)
24 changes: 24 additions & 0 deletions docs/docs/deployment/railway.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Railway

To deploy your own Quirrel server to Railway, click this button:

[![Deploy to Railway](https://railway.app/button.svg)](https://railway.app/new/template/quirrel)

During the process, Railway will clone this repository for you. In there, you find a `Dockerfile`. To pin down your Quirrel version, update its tag:

```diff
- FROM ghcr.io/quirrel-dev/quirrel:main
+ FROM ghcr.io/quirrel-dev/quirrel:sha-f218c98
```

Check Quirrel's [Docker image page](https://github.com/quirrel-dev/quirrel/pkgs/container/quirrel) to find the exact version you want to pin.

Use the `PASSPHRASE` you set during the creation to issue a new token:

```sh
curl --user ignored:<PASSPHRASE> -X PUT https://mighty-owl-production.up.railway.app/tokens/foo
```

You now have your own Quirrel instance 🥳

Next step: [Connecting your application](/deployment/connecting).
21 changes: 21 additions & 0 deletions docs/docs/development.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

# Development

During development, you can use Quirrel's lightweight local server.
This runs entirely on your machine, without needing any database or other external services.

After installing Quirrel via `npm install quirrel`, the local server is started by running `quirrel` in your terminal.
This will start a server and automatically start scanning for CronJobs in your project.
If you're using the default development port of your framework (like `:3000` for Next.js), then Quirrel will automatically detect and use the local server.

You can run `quirrel ui` to open up an admin interface that could be useful in local development.

To always run Quirrel as part of your local development environment, you can add it to your `package.json`:

```json
"scripts": {
"dev": "concurrently 'next dev' 'quirrel'"
}
```
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: Next.js
---
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

# Next.js

This document guides you through setting up Quirrel and creating your first queue in an existing project.

Expand All @@ -10,8 +11,8 @@ If you're looking for a tutorial instead, check out the [Water Drinking Reminder

Architecturally, Quirrel consists of two main parts:

1. The Quirrel *server* receives jobs from your application and then makes requests back to it whenever a job is due.
2. The Quirrel *client* is used by your application to interface with the server.
1. The Quirrel _server_ receives jobs from your application and then makes requests back to it whenever a job is due.
2. The Quirrel _client_ is used by your application to interface with the server.

First, we're gonna setup the Quirrel server locally.
To install it, simply run `npm install quirrel` in your project root,
Expand All @@ -21,21 +22,44 @@ That's it!
:::note
You can use [`concurrently`](https://github.com/kimmobrunfeldt/concurrently)
to have the Quirrel server be started together with Next:

```json
"scripts": {
"dev": "concurrently 'next dev' 'quirrel'"
}
```

:::

This is all we need installed to create our first Queue!

## Your first Queue

Create a new [API Route](https://nextjs.org/docs/api-routes/introduction) at `pages/api/queues/email.js` and paste the following:
<Tabs>
<TabItem value="app" label="App Router">

```js title="pages/api/queues/email.js"
import { Queue } from "quirrel/next"
Create a new [Router Handler](https://nextjs.org/docs/app/building-your-application/routing/router-handlers) at `app/api/queues/email.js` and paste the following:

```typescript title="app/api/queues/email/route.ts"
import { Queue } from "quirrel/next-app"

export const emailQueue = Queue(
"api/queues/email", // 👈 the route it's reachable on
async job => {
await email.send( ... )
}
)

export const POST = emailQueue
```

</TabItem>
<TabItem value="page" label="Pages Router">

Create a new [API Route](https://nextjs.org/docs/api-routes/introduction) at `pages/api/queues/email.js` and paste the following:

```typescript title="pages/api/queues/email.ts"
import { Queue } from "quirrel/next-pages"

export default Queue(
"api/queues/email", // 👈 the route it's reachable on
Expand All @@ -45,6 +69,9 @@ export default Queue(
)
```

</TabItem>
</Tabs>

Up top, we're importing `Queue`, which is a function that we use to declare a new Queue and export it as default.

`Queue` takes two arguments.
Expand All @@ -53,10 +80,31 @@ This is required for the Quirrel server to know where jobs need to be sent upon
The second one is a worker function that actually executes the job.
In this example, it sends an email.


Now that we declared the Queue, using it is straight forward.
Simply import it and enqueue a new job:

<Tabs>
<TabItem value="app" label="App Router">

Create a new [Router Handler](https://nextjs.org/docs/app/building-your-application/routing/router-handlers) at `app/api/queues/email.js` and paste the following:

```ts {6-9}
import { emailQueue } from "app/api/queues/email"

// could be some API route / getServerSideProps / ...
export default async (req, res) => {

await emailQueue.enqueue(
..., // job to be enqueued
{ delay: "24h" } // scheduling options
)

}
```
</TabItem>
<TabItem value="page" label="Pages Router">


```ts {6-9}
import EmailQueue from "pages/api/queues/email"

Expand All @@ -71,6 +119,9 @@ export default async (req, res) => {
}
```

</TabItem>
</Tabs>

Calling `.enqueue` will trigger a call to the Quirrel server to enqueue a new job.
After 24 hours, when the job is due, the Queue's worker function will receive the job payload and execute it.

Expand All @@ -81,4 +132,8 @@ In there, you can also manually invoke jobs, so you don't have to wait for 24 ho

To use it, simply run `quirrel ui` or open [ui.quirrel.dev](https://ui.quirrel.dev) in your browser.

<img src={require("./dev-ui.png").default} alt="Screenshot of the Development UI" height="400rem"/>
<img
src={require("./dev-ui.png").default}
alt="Screenshot of the Development UI"
height="400rem"
/>
Loading