Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

AddWorkerSafely leaves registered kinds after an alias collision

オープン
#1,433 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@flcrom がすでに取り組んでいます。

2026年10月5日 から。

  • #1440 @flcrom による — オープン

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
25/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
停滞
技術スタック
go
領域
backend

調査の方向性

Start by reading worker.go, especially Workers.add, which the issue identifies as writing entries before validating remaining aliases. Use the provided reproducer as the regression test: after a collision, replacement workers for the primary kind and earlier alias should register successfully. An open linked pull request indicates work is already underway.

索引モデルが issue の本文から書いたものです。

説明

When AddWorkerSafely encounters a collision in a later KindAliases entry, it returns an error but leaves the new primary kind and preceding aliases registered. A caller that handles the error cannot subsequently register replacement workers for those kinds.

I reproduced this against current master 6cdaf386c3f672e267ff19a5eb3b105a081171bc, using the public API only, before any client initialization or Start. Workers.add writes entries before validating the remaining aliases.

Reproducer

In a separate Go module, require github.com/riverqueue/river v0.48.1-0.20261004195309-6cdaf386c3f6 and save this as registration_test.go:

package registryprobe

import (
	"context"
	"strings"
	"testing"

	"github.com/riverqueue/river"
)

type occupiedArgs struct{}

func (occupiedArgs) Kind() string { return "probe_occupied" }

type candidateArgs struct{}

func (candidateArgs) Kind() string { return "probe_primary" }
func (candidateArgs) KindAliases() []string {
	return []string{"probe_early_alias", "probe_occupied"}
}

type primaryArgs struct{}

func (primaryArgs) Kind() string { return "probe_primary" }

type earlyAliasArgs struct{}

func (earlyAliasArgs) Kind() string { return "probe_early_alias" }

func addPrimary(workers *river.Workers) error {
	return river.AddWorkerSafely(workers, river.WorkFunc(func(context.Context, *river.Job[primaryArgs]) error { return nil }))
}

func addEarlyAlias(workers *river.Workers) error {
	return river.AddWorkerSafely(workers, river.WorkFunc(func(context.Context, *river.Job[earlyAliasArgs]) error { return nil }))
}

func TestFailedAliasRegistrationLeavesNoNewKinds(t *testing.T) {
	t.Parallel()

	for _, tc := range []struct {
		name                string
		registerReplacement func(*river.Workers) error
	}{
		{"EarlierAlias", addEarlyAlias},
		{"PrimaryKind", addPrimary},
	} {
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			workers := river.NewWorkers()
			if err := river.AddWorkerSafely(workers, river.WorkFunc(func(context.Context, *river.Job[occupiedArgs]) error { return nil })); err != nil {
				t.Fatal(err)
			}
			err := river.AddWorkerSafely(workers, river.WorkFunc(func(context.Context, *river.Job[candidateArgs]) error { return nil }))
			if err == nil || !strings.Contains(err.Error(), "probe_occupied") {
				t.Fatalf("expected occupied-alias collision, got %v", err)
			}
			if err := tc.registerReplacement(workers); err != nil {
				t.Fatalf("failed registration retained %s, preventing recovery: %v", tc.name, err)
			}
		})
	}
}

func TestFreshRegistryControl(t *testing.T) {
	t.Parallel()

	workers := river.NewWorkers()
	if err := addPrimary(workers); err != nil {
		t.Fatal(err)
	}
	if err := addEarlyAlias(workers); err != nil {
		t.Fatal(err)
	}
}

Executed with Go 1.27.1:

go test -mod=readonly -race -p 1 ./... -run 'TestFailedAliasRegistrationLeavesNoNewKinds|TestFreshRegistryControl' -count=1 -timeout=60s -v

Both recovery checks fail:

failed registration retained EarlierAlias, preventing recovery: worker for kind "probe_early_alias" is already registered
failed registration retained PrimaryKind, preventing recovery: worker for kind "probe_primary" is already registered

The fresh-registry control passes. The run used an isolated local module with networking disabled during execution, no database and no running River client. I have not run River's full make test or make lint, and have not implemented a fix.

Should a failed registration leave the workers bundle unchanged? If that is the intended contract, I'd like to address this narrowly in worker.go with regression tests for alias collisions. This would not change ordinary kind renaming or permit registration after Client.Start; I noted the clarification in #335.

AI assistance (OpenAI/Codex) was used to investigate and draft the reproducer/report; the results above are from executing the pinned library, not generated test output.

主要言語
Go
スター
5.7k
フォーク
187
平均マージ
1日 11時間
マージ済み PR(30日)
63

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

riverqueue/river のほかの issue

riverqueue/river の issue をすべて見る

似ている issue

Go の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。