No description
Find a file
2025-02-13 10:24:08 -07:00
.github/workflows chore(deps): remove exp/slog in favor of log/slog 2025-02-13 10:24:08 -07:00
backends chore(deps): remove exp/slog in favor of log/slog 2025-02-13 10:24:08 -07:00
bin Improve dev environment 2024-01-26 09:21:05 -07:00
examples examples: Cleanup 2023-09-24 13:29:33 -06:00
handler chore(deps): remove exp/slog in favor of log/slog 2025-02-13 10:24:08 -07:00
internal feat: Remove dead code 2023-09-02 14:59:32 +02:00
jobs feat: Add public jobs.WithJobContext() 2024-06-07 07:22:07 -07:00
logging chore(deps): remove exp/slog in favor of log/slog 2025-02-13 10:24:08 -07:00
testutils maint: clean up testutils/TestLogger 2023-09-07 12:36:02 +02:00
.envrc Improve dev environment 2024-01-26 09:21:05 -07:00
.gitignore Improve dev environment 2024-01-26 09:21:05 -07:00
.go-version Bump golang version 2023-02-19 10:04:35 -05:00
.golangci.yaml Fix lints 2024-01-26 09:21:05 -07:00
.goreleaser.yaml break: Rename types.Backend -> neoq.Neoq 2023-09-07 12:36:02 +02:00
doc.go Add redis support (#44) 2023-04-14 19:11:22 -06:00
env.sample Update env.sample with better examples 2024-01-19 13:30:04 -07:00
flake.lock Improve dev environment 2024-01-26 09:21:05 -07:00
flake.nix fix(postgres): jobs may never get processed if no workers hear the initial announcement 2025-01-25 13:01:03 -08:00
go.mod chore(deps): remove exp/slog in favor of log/slog 2025-02-13 10:24:08 -07:00
go.sum chore(deps): remove exp/slog in favor of log/slog 2025-02-13 10:24:08 -07:00
gomod2nix.toml chore(deps): remove exp/slog in favor of log/slog 2025-02-13 10:24:08 -07:00
LICENSE.txt Switch to MIT license 2024-01-27 17:21:36 -07:00
Makefile fix: Bare 'make' fails due to go vet 2023-09-26 08:37:45 -06:00
neoq.go fix: unprocessed jobs from unwatched queues block watched queues 2025-02-13 10:24:08 -07:00
neoq_test.go feat: add support for recovery callbacks 2024-04-16 13:52:54 -06:00
README.md README updates 2024-01-26 09:21:05 -07:00

Neoq

Queue-agnostic background job library for Go, with a pleasant API and powerful features.

Go Reference Matrix Chat

Getting Started

See the Getting Started wiki to get started.

About

Neoq is a queue-agnostic background job library for Go, with a pleasant API and powerful features.

Queue-agnostic means that whether you're using an in-memory queue for developing and testing, or Postgres or Redis queue in production -- your job processing code doesn't change. Job handlers are agnostic to the queue providing jobs. It also means that you can mix queue types within a single application. If you have ephemeral or periodic tasks, you may want to process them in an in-memory queue, and use Postgres or Redis queues for jobs requiring queue durability.

Neoq aims to be simple, reliable, easy to integrate, and demand a minimal infrastructure footprint by providing queue backends that match your existing tech stack.

What it does

  • Multiple Backends: In-memory, Postgres, Redis, or user-supplied custom backends.
  • Retries: Jobs may be retried a configurable number of times with exponential backoff and jitter to prevent thundering herds
  • Job uniqueness: jobs are fingerprinted based on their payload and status to prevent job duplication (multiple jobs with the same payload are not re-queued)
  • Job Timeouts: Queue handlers can be configured with per-job timeouts with millisecond accuracy
  • Periodic Jobs: Jobs can be scheduled periodically using standard cron syntax
  • Future Jobs: Jobs can be scheduled in the future
  • Concurrency: Concurrency is configurable for every queue
  • Job Deadlines: If a job doesn't complete before a specific time.Time, the job expires

Getting Started

Getting started is as simple as declaring queue handlers and adding jobs. You can create multiple neoq instances with different backends to meet your application's needs. E.g. an in-memory backend instance for ephemeral jobs and a Postgres backend instance for queue durability between application restarts.

Additional documentation can be found in the wiki: https://github.com/acaloiaro/neoq/wiki

Error handling in this section is excluded for simplicity.

Add queue handlers

Queue handlers listen for Jobs on queues. Jobs may consist of any payload that is JSON-serializable.

Queue Handlers are simple Go functions that accept a Context parameter.

Example: Add a listener on the greetings queue using the default in-memory backend

ctx := context.Background()
nq, _ := neoq.New(ctx, neoq.WithBackend(memory.Backend))
nq.Start(ctx, handler.New("greetings", func(ctx context.Context) (err error) {
  j, _ := jobs.FromContext(ctx)
  log.Println("got job id:", j.ID, "messsage:", j.Payload["message"])
  return
}))

Enqueue jobs

Enqueuing adds jobs to the specified queue to be processed asynchronously.

Example: Add a "Hello World" job to the greetings queue using the default in-memory backend.

ctx := context.Background()
nq, _ := neoq.New(ctx, neoq.WithBackend(memory.Backend))
nq.Enqueue(ctx, &jobs.Job{
  Queue: "greetings",
  Payload: map[string]any{
    "message": "hello world",
  },
})

Redis

Example: Process jobs on the "greetings" queue and add a job to it using the redis backend

ctx := context.Background()
nq, _ := neoq.New(ctx,
  neoq.WithBackend(redis.Backend),
  redis.WithAddr("localhost:6379"),
  redis.WithPassword(""))

nq.Start(ctx, handler.New("greetings", func(ctx context.Context) (err error) {
  j, _ := jobs.FromContext(ctx)
  log.Println("got job id:", j.ID, "messsage:", j.Payload["message"])
  return
}))

nq.Enqueue(ctx, &jobs.Job{
  Queue: "greetings",
  Payload: map[string]interface{}{
    "message": "hello world",
  },
})

Postgres

Example: Process jobs on the "greetings" queue and add a job to it using the postgres backend

ctx := context.Background()
nq, _ := neoq.New(ctx,
  neoq.WithBackend(postgres.Backend),
  postgres.WithConnectionString("postgres://postgres:postgres@127.0.0.1:5432/neoq"),
)

nq.Start(ctx, handler.New("greetings", func(ctx context.Context) (err error) {
  j, _ := jobs.FromContext(ctx)
  log.Println("got job id:", j.ID, "messsage:", j.Payload["message"])
  return
}))

nq.Enqueue(ctx, &jobs.Job{
  Queue: "greetings",
  Payload: map[string]interface{}{
    "message": "hello world",
  },
})

Example Code

Additional example integration code can be found at https://github.com/acaloiaro/neoq/tree/main/examples

Developing

Neoq development is largely based on Nix and devenv.

After installing nix, this repository contains everything else you will need to develop and run tests.

Automatic setup and teardown

See installing direnv if you want the dev environment setup to be automated.

direnv allow allows direnv to automatically setup all tooling and dependencies in a development shell upon entering the neoq directory.

Manual setup and teardown

Neoq uses devenv to manage development environments and services.

To enter the development shell, run nix develop --impure. If devenv is installed, this step is not necessary; simply enter the neoq directory after having run direnv allow.

Running services for tests

The neoq development shell gives you the devenv executable.

To run postgres and redis for tests and development, run

devenv up

This runs Postgres and Redis in the foreground. In a separate terminal, run make test to run the test suite.

Running tests

Before submitting pull requests, always run tests locally with after having run devenv up.

Run make test to run the test suite.

Status

This project is currently pre-1.0. Future releases may change the API.