Skip to content

v0.24.0

Choose a tag to compare

@cuonggt cuonggt released this 30 Sep 02:40
· 62 commits to main since this release

The queue, further: a kind's jobs run so many at once at most, with queue.AtOnce, or start so many a time, with queue.Rate, counted on all the instances of the app together, as a CPU or a mail provider takes only so much however many instances there are; and queue.OnFail, which marks what a job was about once it has failed for good, as a Laravel job's failed method does. A hundred photos to resize no longer take every worker, and a newsletter's ten thousand mails no longer go faster than the provider allows. The auth starter's jobs table keeps both limits, in SQLite, Postgres and MySQL.

queue.Handle(q, "resize-photo", a.resizePhoto, queue.AtOnce(2))

// 14 a second, counted in the auth starter's throttles table, where every instance counts.
perSecond := &auth.Throttle{Name: "newsletter", Max: 14, Window: time.Second, Store: counts}
queue.Handle(q, "newsletter", a.sendNewsletter, queue.Rate(perSecond))

queue.Handle(q, "process-photo", a.processPhoto,
	queue.OnFail(func(ctx context.Context, job ProcessPhoto, err error) error {
		return a.posts.photoFailed(ctx, job.Post, err.Error()) // the post says its photo didn't come
	}),
)

What's new:

  • queue.AtOnce(n): no more than n of a kind's jobs run at once, on all the instances together. A job waits while n of its kind are held by claims, and runs once one is done, has failed or gone back, or has lost its worker. The claim counts, as it passes over a OneAtATime job, so nothing stays locked while the jobs run. Each job carries its kind's limit, Job.AtOnce, which a queue.AtOnceStore keeps.
  • queue.Rate(l): a kind's jobs start no faster than l lets them. l is a queue.Limiter, the Try that auth.Throttle has, so the queue imports no auth, and a rate counts where the throttles do. A job l refuses goes back as it was, its attempts unchanged and its place kept, and no job of its kind is claimed until l's wait is over, on any instance, through a queue.HoldBackStore's HoldBack: the rest of a newsletter waits in the Store, rather than each be claimed and refused in turn. A limiter that fails, as when its store is down, holds the job back for 10 seconds.
  • queue.OnFail(fn): fn gets the value a job was pushed with and the error its last attempt returned, once, after the Store has kept the job as failed for good, on the instance that ran it, with a context done after the kind's Timeout. Its own error, or its panic, goes to the log. Handle panics when fn takes another type than the kind's value.
  • The next job sooner: a job of an AtOnce or OneAtATime kind wakes the queue as it ends, so the next of its kind runs at once, where a OneAtATime kind's waited for the next Poll. And Drain returns once its context is done.
  • queuetest.TestStore checks an AtOnceStore's promises, claims at once among them, and a HoldBackStore's, and queuetest.Memory keeps both.
  • The auth starter's jobs table keeps both limits, in each database: an at_once column, which a claim compares with a count of its kind's held jobs, by a new index on held_until, and on Postgres and MySQL counts again under its kind's job_locks row; and a held_kinds table, of the kinds held back until when, which prune-jobs clears. On MySQL, the claim counts the kinds held back, as a NOT EXISTS there became a join that locked every job it read, so claims at once found none.

Upgrading: nothing an app calls changed: go get github.com/cuonggt/tug@v0.24.0. A kind with AtOnce or Rate needs a Store that's an AtOnceStore or a HoldBackStore, and Handle panics without one, as for Unique's options; an app's own Store keeps working for every other kind. To have the limits in an app made from the auth starter, take jobs_db.go, and KeepsAtOnce from jobs.go, from an app tug new -auth makes on the same database, and its migration step, the at_once column, the jobs_held index and the held_kinds table, three steps on MySQL, at the end of the app's own migrations. docs/jobs.md has the limits, a job that fails for good OnFail, and the Stores their new extras.

The guide is in docs/. tug needs Go 1.26.