Skip to content

Getting Started

Adriano Caloiaro edited this page Sep 16, 2023 · 1 revision

Getting Started

Let's start a project that uses the memory backend.

Don't worry if you have no intention of using the memory backend in production; we're using it here to keep this introduction as simple as possible, by not requiring you to run any additional services. After all, that was a major motivation for building neoq.

You can change backends at any time. The only code that changes when switching backends are the parameters passed to neoq.New. All other code remains the same. So while this Getting Started guide is written for the memory backend, few changes are necessary to switch to postgres or redis.


Begin by initializing a Go project and adding neoq to it:

go mod init example.com/my_app
go get github.com/acaloiaro/neoq/backends/memory

If you'd like to use redis or postgres, simply go get those backends instead of memory. Refer to the Backends article for more details on the backends available to you.

The code

  1. Import the neoq and stdlib packages used throughout this guide main.go:

     import (
     	"context"
     	"log"
    
     	"github.com/acaloiaro/neoq"
     	"github.com/acaloiaro/neoq/backends/memory"
     	"github.com/acaloiaro/neoq/handler"
     	"github.com/acaloiaro/neoq/jobs"
     )
  2. Initialize neoq with the memory backend

     // We're using an `init()` function here to keep our queue listening code in `init()` separate from our enqueuing
     // code  in `main()`, for the  purposes of demonstration. Feel free to initialize neoq at any stage during your your
     // application's  initialization; doing so in an init() function is not a requirement.
     func init() {
     	ctx = context.Background()
     	// neoq.New's second return value is an `error`, but we're avoiding error handling here for simplicity
     	// `nq` is what we'll use to Enqueue new jobs and Start/Stop workers
     	nq, _ = neoq.New(ctx, neoq.WithBackend(memory.Backend))
    
     	// create a handler that listens for new job on the "greetings" queue
     	h := handler.New("greetings", func(ctx context.Context) (err error) {
     		j, _ := jobs.FromContext(ctx)
     		log.Printf("Hello, %s!", j.Payload["Name"])
     		done <- true
     		return
     	})
    
     	// Start starts listening for jobs on a queue with the given handler
     	// If you have many jobs, which is usual, call Start() for every queue/Handler in your application
     	nq.Start(ctx, h)
     }
  3. Enqueue a job and wait for the job to complete. Since our Handler writes to done on completion, we can listen on done to wait for completion after the job has been enqueued.

     func main() {
     	// be sure to shut down neoq before exiting to allow it to gracefully finish up any work in progress
     	defer func() { nq.Shutdown(ctx) }()
    
     	// Create a job to place on the queue. A job must specify a queue, but its payload may be empty
     	j := &jobs.Job{Queue: "greetings", Payload: map[string]any{"Name": "World"}}
    
     	// Enqueue the job for processing. Enqueue()'s first return value is the queued job's ID
     	_, err := nq.Enqueue(context.Background(), j)
     	if err != nil {
     		log.Fatalf("Unable to enqueue job: %s", err)
     	}
    
     	// wait for the job to process before exiting 
     	<-done
     }

Upon completion, you will see the following greeting printed to the screen (with different timestamps, of course).

2023/09/15 17:49:23 Hello, World!

Congratulations! You've enqueued you first neoq job.

main.go

package main

import (
	"context"
	"log"

	"github.com/acaloiaro/neoq"
	"github.com/acaloiaro/neoq/backends/memory"
	"github.com/acaloiaro/neoq/handler"
	"github.com/acaloiaro/neoq/jobs"
)

var (
	done = make(chan bool)
	nq   neoq.Neoq
	ctx  context.Context
)

// We're using an `init()` function here to keep our queue listening code in `init()` separate from our enqueuing
// code  in `main()`, for the  purposes of demonstration. Feel free to initialize neoq at any stage during your your
// application's  initialization; doing so in an init() function is not a requirement.
func init() {
	ctx = context.Background()

	// neoq.New's second return value is an `error`, but we're avoiding error handling here for simplicity
	// `nq` is what we'll use to Enqueue new jobs and Start/Stop workers
	nq, _ = neoq.New(ctx, neoq.WithBackend(memory.Backend))

	// create a handler that listens for new job on the "greetings" queue
	h := handler.New("greetings", func(ctx context.Context) (err error) {
		j, _ := jobs.FromContext(ctx)
		log.Printf("Hello, %s!", j.Payload["Name"])
		done <- true
		return
	})

	// Start starts listening for jobs on a queue with the given handler
	// If you have many jobs, which is usual, call Start() for every queue/Handler in your application
	nq.Start(ctx, h)
}

func main() {
	// be sure to shut down neoq before exiting to allow it to gracefully finish up any work in progress
	defer func() { nq.Shutdown(ctx) }()

	// Create a job to place on the queue. A job must specify a queue, but its payload may be empty
	j := &jobs.Job{Queue: "greetings", Payload: map[string]any{"Name": "World"}}

	// Enqueue the job for processing. Enqueue()'s first return value is the queued job's ID
	_, err := nq.Enqueue(context.Background(), j)
	if err != nil {
		log.Fatalf("Unable to enqueue job: %s", err)
	}

	// wait until at least one job gets processed to exit
	<-done
}

Further reading

For API documenation and more usage examples, please refer to the neoq package documentation: https://pkg.go.dev/github.com/acaloiaro/neoq.

Clone this wiki locally