AddService adds a microservice. It will enable internal common services (PING, STATS and INFO). Request handlers have to be registered separately using Service.AddEndpoint. A service name, version and Endpoint configuration are required to add a service. AddService returns a [Service] interface, all
(nc *nats.Conn, config Config)
| 323 | // AddService returns a [Service] interface, allowing service management. |
| 324 | // Each service is assigned a unique ID. |
| 325 | func AddService(nc *nats.Conn, config Config) (Service, error) { |
| 326 | if err := config.valid(); err != nil { |
| 327 | return nil, err |
| 328 | } |
| 329 | |
| 330 | if config.Metadata == nil { |
| 331 | config.Metadata = map[string]string{} |
| 332 | } |
| 333 | |
| 334 | id := nuid.Next() |
| 335 | svc := &service{ |
| 336 | Config: config, |
| 337 | nc: nc, |
| 338 | id: id, |
| 339 | asyncDispatcher: asyncCallbacksHandler{ |
| 340 | cbQueue: make(chan func(), 100), |
| 341 | }, |
| 342 | verbSubs: make(map[string]*nats.Subscription), |
| 343 | endpoints: make([]*Endpoint, 0), |
| 344 | } |
| 345 | |
| 346 | // Add connection event (closed, error) wrapper handlers. If the service has |
| 347 | // custom callbacks, the events are queued and invoked by the same |
| 348 | // goroutine, starting now. |
| 349 | go svc.asyncDispatcher.run() |
| 350 | svc.wrapConnectionEventCallbacks() |
| 351 | |
| 352 | if config.Endpoint != nil { |
| 353 | opts := []EndpointOpt{WithEndpointSubject(config.Endpoint.Subject)} |
| 354 | if config.Endpoint.Metadata != nil { |
| 355 | opts = append(opts, WithEndpointMetadata(config.Endpoint.Metadata)) |
| 356 | } |
| 357 | if config.Endpoint.QueueGroup != "" { |
| 358 | opts = append(opts, WithEndpointQueueGroup(config.Endpoint.QueueGroup)) |
| 359 | } else if config.QueueGroup != "" { |
| 360 | opts = append(opts, WithEndpointQueueGroup(config.QueueGroup)) |
| 361 | } |
| 362 | if err := svc.AddEndpoint("default", config.Endpoint.Handler, opts...); err != nil { |
| 363 | svc.asyncDispatcher.close() |
| 364 | return nil, err |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | // Setup internal subscriptions. |
| 369 | pingResponse := Ping{ |
| 370 | ServiceIdentity: svc.serviceIdentity(), |
| 371 | Type: PingResponseType, |
| 372 | } |
| 373 | |
| 374 | handleVerb := func(verb Verb, valuef func() any) func(req Request) { |
| 375 | return func(req Request) { |
| 376 | response, _ := json.Marshal(valuef()) |
| 377 | if err := req.Respond(response); err != nil { |
| 378 | if err := req.Error("500", fmt.Sprintf("Error handling %s request: %s", verb, err), nil); err != nil && config.ErrorHandler != nil { |
| 379 | svc.asyncDispatcher.push(func() { |
| 380 | config.ErrorHandler(svc, &NATSError{Subject: req.Subject(), Description: err.Error(), err: err}) |
| 381 | }) |
| 382 | } |