River 0.4.0: A few breaking changes
This morning River 0.4.0 was cut, which for the first time in the project's release history, contains breaking changes. There was a bit of an internal debate on the philosophy of whether breaking changes were are worth it even if they do improve the API, but since the project's pre-V1 and the breakages are all quite small (most projects probably won't need to be updated), they shipped.
It'll sound counterintuitive, but in pursuit of minimizing pain, they're all going out in a single release. The hope is that any fixing effort involved is consolidated in a single upgrade, and that this kind of rare event won't happen again for a long time.
Job list API
JobListParams.State
becomes JobListParams.States
and can take more than one job state to filter on.
listRes, err := client.JobList(ctx, NewJobListParams().States(
rivertype.JobStateRunning,
rivertype.JobStateRetryable,
))
Job listing now defaults to being order by ID instead of best fit timestamp. Projects can keep using the old behavior by explicitly specifying JobListOrderByTime
:
river.NewJobListParams().OrderBy(JobListOrderByTime, SortOrderAsc)
JobListCursorFromJob
no longer takes a sort order, instead procuring it when applied to a set of list parameters using JobListParams.After
. The function now takes only a single parameter, the job row to act as cursor:
cursor := river.JobListCursorFromJob(jobRow)
Insert results
The client's Insert
and InsertTx
functions now return a JobInsertResult
struct instead of raw JobRow
. This leaves room in the result to include useful metadata like the new UniqueSkippedAsDuplicate
property, so callers can tell whether an inserted job was skipped due to unique constraint.
insertRes, err := riverClient.Insert(ctx, MyArgs{...}, nil)
// true if job was skipped because of a preexisting unique equivalent
insertRes.UniqueSkippedAsDuplicate
Pointer-sized ints preferred
The client's InsertMany
and InsertManyTx
now return number of jobs inserted as int
instead of int64
. This is a tiny tweak made so that the type in use is a little more idiomatic according to Go convention. We wouldn't have bothered unless other breaking changes were going out at the same time.
Job state aliases removed
The river.JobState*
type aliases have been removed. All job state constants should be accessed through the canonical set of rivertype.JobState*
constants instead.
This is another one that we wouldn't have otherwise bothered with, but removing the aliases tightens up the API in small ways that are desirable. The change means that there's now only one way of doing things (instead of having to choose between river.JobStateAvailable
or rivertype.JobStateAvailable
, both of which used to work), and aliases make the IDE experience a little suboptimal because using "jump to definition" requires an intermediate hop through the alias first.
Shallow cuts
We hate shipping API breakages as much as programmers hate integrating them, but there's some good news:
None of River's core APIs around working jobs change, and since the return value of
Insert
/InsertTx
is often ignored anyway, many projects using River won't have to change any code.All problems will be detected by Go's compiler. Since resolutions for each are trivial, upgrading projects that were affected will be fast.
An initial goal of the project was to take enough care with the initial API design that it'll never need a /v2
. The changes above represent a few misses, but we consider it good news that nothing more fundamental has come up in the intervening months, and we're still on track for a single major version.