feat(worker): adopt canonical public URL
Все проверки выполнены успешно
CI / test (push) Successful in 10m15s
Docker / Build and publish worker image (push) Successful in 34m59s

Этот коммит содержится в:
Gleb Tv
2026-08-12 20:48:01 +03:00
родитель a1ccd50aaf
Коммит cb23f123ae
19 изменённых файлов: 804 добавлений и 74 удалений

Просмотреть файл

@@ -4,10 +4,15 @@ package wire
import "encoding/json"
// RegisterRequest is sent to the control plane registration API.
// PublicURL is the canonical advertised origin (scheme and authority
// only, see docs/public-endpoint-and-identity.md). The legacy URL field
// remains on the wire for the bounded migration from WORKER_URL; new
// senders populate PublicURL and old control planes keep reading URL.
type RegisterRequest struct {
WorkerID string `json:"worker_id" binding:"required"`
RegionCode string `json:"region_code" binding:"required"`
Version string `json:"version"`
PublicURL string `json:"public_url,omitempty"`
URL string `json:"url,omitempty"`
Capabilities []string `json:"capabilities"`
TaskEnvelope bool `json:"task_envelope"`
@@ -203,6 +208,9 @@ type PeerInfo struct {
}
// WorkerInit is sent by the control plane after websocket authentication.
// PublicURL is the canonical advertised origin accepted by the control
// plane; URL is the legacy wire field kept for the bounded migration.
// A worker must prefer PublicURL when it is non-empty.
type WorkerInit struct {
WorkerID string `json:"worker_id"`
RegionCode string `json:"region_code"`
@@ -211,6 +219,7 @@ type WorkerInit struct {
NotificationMethods []string `json:"notification_methods,omitempty"`
NotificationAccounts []int64 `json:"notification_accounts,omitempty"`
Concurrency int `json:"concurrency"`
PublicURL string `json:"public_url,omitempty"`
URL string `json:"url,omitempty"`
ServerID *int64 `json:"server_id,omitempty"`
LLMs []LLMConfig `json:"llms,omitempty"`

Просмотреть файл

@@ -151,6 +151,82 @@ func TestRegisterRequest_URLOmittedWhenEmpty(t *testing.T) {
require.NoError(t, err)
assert.False(t, strings.Contains(string(data), `"url"`),
"empty URL must be omitted from the register payload, got %s", string(data))
assert.False(t, strings.Contains(string(data), `"public_url"`),
"empty PublicURL must be omitted from the register payload, got %s", string(data))
}
// TestRegisterRequest_PublicURLRoundTrip verifies the canonical public_url
// wire field serializes and deserializes alongside the legacy url field.
func TestRegisterRequest_PublicURLRoundTrip(t *testing.T) {
req := RegisterRequest{
WorkerID: "worker-eu-1",
RegionCode: "eu",
Version: "v1",
PublicURL: "https://worker-eu.example.com",
}
data, err := json.Marshal(req)
require.NoError(t, err)
assert.Contains(t, string(data), `"public_url":"https://worker-eu.example.com"`,
"PublicURL must serialize as the top-level public_url field, got %s", string(data))
var decoded RegisterRequest
require.NoError(t, json.Unmarshal(data, &decoded))
assert.Equal(t, "https://worker-eu.example.com", decoded.PublicURL)
}
// TestWorkerInit_PublicURLRoundTrip covers the canonical public_url field
// on the init/config frame.
func TestWorkerInit_PublicURLRoundTrip(t *testing.T) {
init := WorkerInit{
WorkerID: "worker-1",
RegionCode: "ru",
Version: "v1",
Concurrency: 4,
PublicURL: "https://worker-eu.example.com",
}
data, err := json.Marshal(init)
require.NoError(t, err)
assert.Contains(t, string(data), `"public_url":"https://worker-eu.example.com"`,
"PublicURL must serialize as a top-level public_url field, got %s", string(data))
var decoded WorkerInit
require.NoError(t, json.Unmarshal(data, &decoded))
assert.Equal(t, "https://worker-eu.example.com", decoded.PublicURL)
assert.Equal(t, "", decoded.URL,
"legacy URL field must stay empty when only public_url is set")
}
// TestWorkerInit_LegacyURLFieldStillDecodes keeps the bounded-migration
// contract: a control plane that still sends the legacy url field must
// remain wire-compatible with the new worker struct.
func TestWorkerInit_LegacyURLFieldStillDecodes(t *testing.T) {
data := []byte(`{"worker_id":"worker-1","region_code":"ru","concurrency":4,"url":"https://legacy.example.com"}`)
var decoded WorkerInit
require.NoError(t, json.Unmarshal(data, &decoded))
assert.Equal(t, "https://legacy.example.com", decoded.URL)
assert.Equal(t, "", decoded.PublicURL)
}
// TestWorkerInit_PublicURLAndLegacyCoexist ensures a frame that carries
// both fields keeps both on the wire for old and new control planes.
func TestWorkerInit_PublicURLAndLegacyCoexist(t *testing.T) {
init := WorkerInit{
WorkerID: "w-1",
PublicURL: "https://canonical.example.com",
URL: "https://legacy.example.com",
}
data, err := json.Marshal(init)
require.NoError(t, err)
out := string(data)
assert.Contains(t, out, `"public_url":"https://canonical.example.com"`)
assert.Contains(t, out, `"url":"https://legacy.example.com"`)
var decoded WorkerInit
require.NoError(t, json.Unmarshal(data, &decoded))
assert.Equal(t, "https://canonical.example.com", decoded.PublicURL)
assert.Equal(t, "https://legacy.example.com", decoded.URL)
}
// TestWorkerInit_NotificationCapabilitiesRoundTrip ensures the