diff --git a/services/src/service.ts b/services/src/service.ts index c6d0e1b2..f20c7807 100644 --- a/services/src/service.ts +++ b/services/src/service.ts @@ -162,7 +162,7 @@ export class ServiceGroupImpl implements ServiceGroup { } else if (parent instanceof ServiceGroupImpl) { const sg = parent as ServiceGroupImpl; this.srv = sg.srv; - if (queue === "" && sg.queue !== "") { + if (queue === undefined) { queue = sg.queue; } root = sg.subject; @@ -198,7 +198,10 @@ export class ServiceGroupImpl implements ServiceGroup { return this.srv._addEndpoint(ne); } - addGroup(name = "", queue = ""): ServiceGroup { + addGroup(name = "", queue?: string): ServiceGroup { + if (queue === undefined) { + queue = this.queue; + } return new ServiceGroupImpl(this, name, queue); } } @@ -286,13 +289,18 @@ export class ServiceImpl implements Service { ) { this.nc = nc; this.config = Object.assign({}, config); - if (!this.config.queue) { + if (this.config.queue === undefined) { this.config.queue = "q"; } + // don't allow changing metadata + config.metadata = Object.freeze(config.metadata || {}); + // this will throw if no name validateName("name", this.config.name); - validateName("queue", this.config.queue); + if (this.config.queue) { + validateName("queue", this.config.queue); + } // this will throw if not semver parseSemVer(this.config.version); diff --git a/services/src/types.ts b/services/src/types.ts index ae9cbb7e..39d6ed74 100644 --- a/services/src/types.ts +++ b/services/src/types.ts @@ -51,7 +51,8 @@ export type Endpoint = { metadata?: Record; /** * Optional queue group to run this particular endpoint in. The service's configuration - * queue configuration will be used. See {@link ServiceConfig}. + * queue configuration will be used. See {@link ServiceConfig}. Note that if the queue + * is set to an empty string, it will not be run in a queue. */ queue?: string; }; @@ -81,6 +82,8 @@ export interface ServiceGroup { * without requiring editing of the service. * Note that an optional queue can be specified, all endpoints added to * the group, will use the specified queue unless the endpoint overrides it. + * When not set, it uses the parent group configuration. An empty string + * means no queue. * see {@link EndpointOptions} and {@link ServiceConfig}. * @param subject * @param queue @@ -208,9 +211,11 @@ export type ServiceConfig = { */ metadata?: Record; /** - * Optional queue group to run the service in. By default, - * then queue name is "q". Note that this configuration will - * be the default for all endpoints and groups. + * Optional queue group to run the service in. If not set, default, + * is set to "q". Note that this configuration will + * be the default for all endpoints and groups. If set to an empty + * string, the service subscription will NOT have queue, and will + * not be run in a queue. */ queue?: string; }; diff --git a/services/tests/service_test.ts b/services/tests/service_test.ts index 1ed9058e..35f5f958 100644 --- a/services/tests/service_test.ts +++ b/services/tests/service_test.ts @@ -1047,3 +1047,61 @@ Deno.test("service - endpoint default queue group", async () => { await cleanup(ns, nc); }); + +Deno.test("service - endpoint no queue group", async () => { + const { ns, nc } = await setup(); + + const svc = new Svc(nc); + const srv = await svc.add({ + name: "example", + version: "0.0.1", + metadata: { service: "1" }, + // no queue + queue: "", + }) as ServiceImpl; + + // svc config doesn't specify a queue group so we expect q + srv.addEndpoint("a"); + checkQueueGroup(srv, "a", ""); + + // we add another group, no queue + const dg = srv.addGroup("G"); + dg.addEndpoint("a"); + checkQueueGroup(srv, "G.a", ""); + + // the above have no queue, no override, and set a queue + const g = srv.addGroup("g", "qq"); + g.addEndpoint("a"); + checkQueueGroup(srv, "g.a", "qq"); + // override + g.addEndpoint("b", { queue: "bb" }); + checkQueueGroup(srv, "g.b", "bb"); + // add a subgroup without, should inherit + const g2 = g.addGroup("g"); + g2.addEndpoint("a"); + checkQueueGroup(srv, "g.g.a", "qq"); + + await cleanup(ns, nc); +}); + +Deno.test("service - metadata is not editable", async () => { + const { ns, nc } = await setup(); + + const svc = new Svc(nc); + const srv = await svc.add({ + name: "example", + version: "0.0.1", + metadata: { service: "1", hello: "world" }, + queue: "", + }) as ServiceImpl; + + assertThrows( + () => { + srv.config.metadata!.hello = "hello"; + }, + TypeError, + "Cannot assign to read only property", + ); + + await cleanup(ns, nc); +});