Routes may share one lease (affinity = "route") and skip crossbar's queue (queue = false)
route.go gains Route.Affinity/Queue with PerRoute(), Queues() and affinity validation (checkRoutes moved here; config.go calls it once). limiter.Track counts a request without holding or refusing it; a release hands the slot to a waiter only while in flight <= parallel. The proxy leases a PerRoute() route under an empty fingerprint (the row keeps the real one) and uses Track when Queues() is false. Implemented by Ornith (OpenCode); owner review removed a release-on-first-flush workaround for a race in the owner's given test (see implementer log). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
package config_test
|
||||
|
||||
// v2.3 task 02: the affinity and queue route keys.
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.wntrmute.dev/kyle/crossbar/internal/config"
|
||||
)
|
||||
|
||||
const affinityBase = `
|
||||
listen = "127.0.0.1:1"
|
||||
[hosts.a]
|
||||
base_url = "http://a:1"
|
||||
models = { "m" = { } }
|
||||
[routes.plain]
|
||||
hosts = ["a"]
|
||||
[routes.convo]
|
||||
hosts = ["a"]
|
||||
affinity = "conversation"
|
||||
[routes.boxmaker]
|
||||
hosts = ["a"]
|
||||
affinity = "route"
|
||||
queue = false
|
||||
[routes."bm-*"]
|
||||
hosts = ["a"]
|
||||
affinity = "route"
|
||||
queue = false
|
||||
[routes.queued]
|
||||
hosts = ["a"]
|
||||
queue = true
|
||||
`
|
||||
|
||||
func TestAffinityAndQueueKeys(t *testing.T) {
|
||||
c, err := config.Parse(strings.NewReader(affinityBase))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
route string
|
||||
perRoute, queues bool
|
||||
}{
|
||||
{"plain", false, true}, // defaults: conversation affinity, queueing on
|
||||
{"convo", false, true},
|
||||
{"boxmaker", true, false},
|
||||
{"bm-agent-1", true, false}, // a template's keys reach its concrete routes
|
||||
{"queued", false, true},
|
||||
} {
|
||||
r, _, ok := c.Route(tc.route)
|
||||
if !ok {
|
||||
t.Fatalf("route %q not found", tc.route)
|
||||
}
|
||||
if r.PerRoute() != tc.perRoute || r.Queues() != tc.queues {
|
||||
t.Errorf("%s: PerRoute %v Queues %v, want %v %v", tc.route, r.PerRoute(), r.Queues(), tc.perRoute, tc.queues)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAffinityRejectsUnknownValues(t *testing.T) {
|
||||
for _, bad := range []string{`"session"`, `"Route"`, `1`} {
|
||||
text := strings.Replace(affinityBase, `affinity = "conversation"`, "affinity = "+bad, 1)
|
||||
_, err := config.Parse(strings.NewReader(text))
|
||||
if err == nil || !strings.Contains(err.Error(), "routes.convo.affinity") {
|
||||
t.Errorf("affinity = %s: err %v, want one naming routes.convo.affinity", bad, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueueMustBeABool(t *testing.T) {
|
||||
text := strings.Replace(affinityBase, "queue = true", `queue = "no"`, 1)
|
||||
if _, err := config.Parse(strings.NewReader(text)); err == nil {
|
||||
t.Error(`queue = "no" parsed; want an error`)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user