Skip to content
MigrationDocs 1.3.x

Service Catalog Checks ​

Applies to @connectum/core 1.3.0.

Does this apply to you? ​

You need to act only if one of these is true:

  • code matches Code.Unavailable on a ctx.call or ctx.stream to a service that is not mounted locally on a server that has no remoteResolver;
  • you pass timeoutMs of 0, a negative number, NaN or Infinity in CallOptions;
  • propagateHeaders holds a name that is not a valid HTTP header name, or is not an array;
  • enabledServices holds a type name that is not in services (for example a typo read from an environment variable);
  • your catalog is a hand-built map whose key differs from its descriptor's typeName;
  • you call createCatalogClient() without a resolver, dnsResolver() without a template, or pass a non-object map to perServiceEnvResolver() or mapResolver();
  • you define the same service twice, or a handler object has a member that is not a function, or a defineLazyService factory is async or returns something that is not an object.

Valid configurations behave as before.

What changed ​

CaseBeforeFrom 1.3.0
ctx.call / ctx.stream to an unmounted service, no remoteResolverCode.Unavailable, "the resolver returned null"Code.FailedPrecondition, "not mounted locally and no remoteResolver is configured"
CallOptions.timeoutMs of 0, negative, NaN, Infinity0 and negatives removed the inherited deadline; the others failed differently locally and remotelyRejected with Code.InvalidArgument naming timeoutMs
Nested call after the inbound deadline passedThe callee ran without a deadlineCode.DeadlineExceeded
Invalid propagateHeaders entrycreateServer() succeeded; every ctx.call threw a TypeErrorcreateServer() throws a TypeError naming propagateHeaders and the entry
enabledServices entry that matches no supplied serviceThe server started with nothing mountedstart() rejects with CatalogConfigError
Catalog key different from the typeNameAcceptedcreateServer() / createCatalogClient() throw CatalogConfigError
Resolver returns a string, undefined or a Promisetransport.unary is not a function on every call; the value was cachedCode.Internal naming the service; not cached
Same service defined twiceThe last definition won silentlyCatalogConfigError
defineService / defineLazyService handler mistakesLate or unnamed errors, or a service whose methods were all unimplementedTypeError naming the service
endpoint: ""The resolver saw { typeName, endpoint: "" } or { typeName } depending on call orderAlways { typeName }
server.hasService() on a lazy serviceRan the factory and froze addService()A lookup; nothing runs

Required changes ​

  • Match the code that fits the cause. For a missing remoteResolver handle Code.FailedPrecondition (or better, configure the resolver or mount the service). Keep Code.Unavailable for a configured resolver that returns null.
  • Drop non-positive timeouts. Omit timeoutMs to inherit the deadline, or pass a positive finite number to shorten it.
  • Fix the names. Correct the header names, enabledServices entries and catalog keys the errors point at.
  • Make factories synchronous. A defineLazyService factory returns the handlers object; do asynchronous setup before createServer().

Before and after ​

typescript
const server = createServer({
  services: [orders],
  catalog,
  enabledServices: [OrdersService.typeName],
  // no remoteResolver
});

// 1.2: ctx.call('inventory.v1.InventoryService/Check', ...) -> Code.Unavailable (retried by `retry`)
// 1.3: ctx.call('inventory.v1.InventoryService/Check', ...) -> Code.FailedPrecondition

Verify the upgrade ​

Start every server configuration you deploy, including the one that reads enabledServices from the environment. start() and createServer() now report the mistakes above before the first request.