github.com/wfusion/gofusion@v1.1.14/common/infra/watermill/message/router.go (about) 1 package message 2 3 import ( 4 "context" 5 "fmt" 6 "runtime/debug" 7 "sync" 8 "time" 9 10 "github.com/pkg/errors" 11 12 "github.com/wfusion/gofusion/common/infra/watermill" 13 "github.com/wfusion/gofusion/common/infra/watermill/pkg" 14 "github.com/wfusion/gofusion/common/utils" 15 ) 16 17 var ( 18 // ErrOutputInNoPublisherHandler happens when a handler func returned some messages in a no-publisher handler. 19 // todo: maybe change the handler func signature in no-publisher handler so that there's no possibility for this 20 ErrOutputInNoPublisherHandler = errors.New("returned output messages in a handler without publisher") 21 ErrRouterIsAlreadyRunning = errors.New("router is already running") 22 ) 23 24 // HandlerFunc is function called when message is received. 25 // 26 // msg.Ack() is called automatically when HandlerFunc doesn't return error. 27 // When HandlerFunc returns error, msg.Nack() is called. 28 // When msg.Ack() was called in handler and HandlerFunc returns error, 29 // msg.Nack() will be not sent because Ack was already sent. 30 // 31 // HandlerFunc's are executed parallel when multiple messages was received 32 // (because msg.Ack() was sent in HandlerFunc or Subscriber supports multiple consumers). 33 type HandlerFunc func(msg *Message) ([]*Message, error) 34 35 // NoPublishHandlerFunc is HandlerFunc alternative, which doesn't produce any messages. 36 type NoPublishHandlerFunc func(msg *Message) error 37 38 // PassthroughHandler is a handler that passes the message unchanged from the subscriber to the publisher. 39 var PassthroughHandler HandlerFunc = func(msg *Message) ([]*Message, error) { 40 return []*Message{msg}, nil 41 } 42 43 // HandlerMiddleware allows us to write something like decorators to HandlerFunc. 44 // It can execute something before handler (for example: modify consumed message) 45 // or after (modify produced messages, ack/nack on consumed message, handle errors, logging, etc.). 46 // 47 // It can be attached to the router by using `AddMiddleware` method. 48 // 49 // Example: 50 // 51 // func ExampleMiddleware(h message.HandlerFunc) message.HandlerFunc { 52 // return func(message *message.Message) ([]*message.Message, error) { 53 // fmt.Println("executed before handler") 54 // producedMessages, err := h(message) 55 // fmt.Println("executed after handler") 56 // 57 // return producedMessages, err 58 // } 59 // } 60 type HandlerMiddleware func(h HandlerFunc) HandlerFunc 61 62 // RouterPlugin is function which is executed on Router start. 63 type RouterPlugin func(*Router) error 64 65 // PublisherDecorator wraps the underlying Publisher, adding some functionality. 66 type PublisherDecorator func(pub Publisher) (Publisher, error) 67 68 // SubscriberDecorator wraps the underlying Subscriber, adding some functionality. 69 type SubscriberDecorator func(sub Subscriber) (Subscriber, error) 70 71 // RouterConfig holds the Router's configuration options. 72 type RouterConfig struct { 73 // CloseTimeout determines how long router should work for handlers when closing. 74 CloseTimeout time.Duration 75 } 76 77 func (c *RouterConfig) setDefaults() { 78 if c.CloseTimeout == 0 { 79 c.CloseTimeout = time.Second * 30 80 } 81 } 82 83 // Validate returns Router configuration error, if any. 84 func (c RouterConfig) Validate() error { 85 return nil 86 } 87 88 // NewRouter creates a new Router with given configuration. 89 func NewRouter(config RouterConfig, logger watermill.LoggerAdapter) (*Router, error) { 90 config.setDefaults() 91 if err := config.Validate(); err != nil { 92 return nil, errors.Wrap(err, "invalid config") 93 } 94 95 if logger == nil { 96 logger = watermill.NopLogger{} 97 } 98 99 return &Router{ 100 config: config, 101 102 handlers: map[string]*handler{}, 103 104 handlersWg: &sync.WaitGroup{}, 105 106 runningHandlersWg: &sync.WaitGroup{}, 107 108 handlerAdded: make(chan struct{}), 109 110 handlersLock: &sync.RWMutex{}, 111 112 ClosingInProgressCh: make(chan struct{}), 113 ClosedCh: make(chan struct{}), 114 115 logger: logger, 116 117 running: make(chan struct{}), 118 }, nil 119 } 120 121 type middleware struct { 122 Handler HandlerMiddleware 123 HandlerName string 124 IsRouterLevel bool 125 } 126 127 // Router is responsible for handling messages from subscribers using provided handler functions. 128 // 129 // If the handler function returns a message, the message is published with the publisher. 130 // You can use middlewares to wrap handlers with common logic like logging, instrumentation, etc. 131 type Router struct { 132 config RouterConfig 133 134 middlewares []middleware 135 136 plugins []RouterPlugin 137 138 handlers map[string]*handler 139 handlersLock *sync.RWMutex 140 141 handlersWg *sync.WaitGroup 142 143 runningHandlersWg *sync.WaitGroup 144 145 handlerAdded chan struct{} 146 147 ClosingInProgressCh chan struct{} 148 ClosedCh chan struct{} 149 closed bool 150 closedLock sync.Mutex 151 152 logger watermill.LoggerAdapter 153 154 publisherDecorators []PublisherDecorator 155 subscriberDecorators []SubscriberDecorator 156 157 isRunning bool 158 running chan struct{} 159 } 160 161 // Logger returns the Router's logger. 162 func (r *Router) Logger() watermill.LoggerAdapter { 163 return r.logger 164 } 165 166 // AddMiddleware adds a new middleware to the router. 167 // 168 // The order of middleware matters. Middleware added at the beginning is executed first. 169 func (r *Router) AddMiddleware(m ...HandlerMiddleware) { 170 r.logger.Debug("[Common] watermill adding middleware", 171 watermill.LogFields{"count": fmt.Sprintf("%d", len(m))}) 172 173 r.addRouterLevelMiddleware(m...) 174 } 175 176 func (r *Router) addRouterLevelMiddleware(m ...HandlerMiddleware) { 177 for _, handlerMiddleware := range m { 178 middleware := middleware{ 179 Handler: handlerMiddleware, 180 HandlerName: "", 181 IsRouterLevel: true, 182 } 183 r.middlewares = append(r.middlewares, middleware) 184 } 185 } 186 187 func (r *Router) addHandlerLevelMiddleware(handlerName string, m ...HandlerMiddleware) { 188 for _, handlerMiddleware := range m { 189 middleware := middleware{ 190 Handler: handlerMiddleware, 191 HandlerName: handlerName, 192 IsRouterLevel: false, 193 } 194 r.middlewares = append(r.middlewares, middleware) 195 } 196 } 197 198 // AddPlugin adds a new plugin to the router. 199 // Plugins are executed during startup of the router. 200 // 201 // A plugin can, for example, close the router after SIGINT or SIGTERM is sent to the process (SignalsHandler plugin). 202 func (r *Router) AddPlugin(p ...RouterPlugin) { 203 r.logger.Debug("Adding plugins", watermill.LogFields{"count": fmt.Sprintf("%d", len(p))}) 204 205 r.plugins = append(r.plugins, p...) 206 } 207 208 // AddPublisherDecorators wraps the router's Publisher. 209 // The first decorator is the innermost, i.e. calls the original publisher. 210 func (r *Router) AddPublisherDecorators(dec ...PublisherDecorator) { 211 r.logger.Debug("Adding publisher decorators", watermill.LogFields{"count": fmt.Sprintf("%d", len(dec))}) 212 213 r.publisherDecorators = append(r.publisherDecorators, dec...) 214 } 215 216 // AddSubscriberDecorators wraps the router's Subscriber. 217 // The first decorator is the innermost, i.e. calls the original subscriber. 218 func (r *Router) AddSubscriberDecorators(dec ...SubscriberDecorator) { 219 r.logger.Debug("Adding subscriber decorators", watermill.LogFields{"count": fmt.Sprintf("%d", len(dec))}) 220 221 r.subscriberDecorators = append(r.subscriberDecorators, dec...) 222 } 223 224 // Handlers returns all registered handlers. 225 func (r *Router) Handlers() map[string]HandlerFunc { 226 handlers := map[string]HandlerFunc{} 227 228 for handlerName, handler := range r.handlers { 229 handlers[handlerName] = handler.handlerFunc 230 } 231 232 return handlers 233 } 234 235 // DuplicateHandlerNameError is sent in a panic when you try to add a second handler with the same name. 236 type DuplicateHandlerNameError struct { 237 HandlerName string 238 } 239 240 func (d DuplicateHandlerNameError) Error() string { 241 return fmt.Sprintf("handler with name %s already exists", d.HandlerName) 242 } 243 244 // AddHandler adds a new handler. 245 // 246 // handlerName must be unique. For now, it is used only for debugging. 247 // 248 // subscribeTopic is a topic from which handler will receive messages. 249 // 250 // publishTopic is a topic to which router will produce messages returned by handlerFunc. 251 // When handler needs to publish to multiple topics, 252 // it is recommended to just inject Publisher to Handler or implement middleware 253 // which will catch messages and publish to topic based on metadata for example. 254 // 255 // If handler is added while router is already running, you need to explicitly call RunHandlers(). 256 func (r *Router) AddHandler( 257 handlerName string, 258 subscribeTopic string, 259 subscriber Subscriber, 260 publishTopic string, 261 publisher Publisher, 262 handlerFunc HandlerFunc, 263 ) *Handler { 264 r.logger.Info("[Common] watermill adding handler", watermill.LogFields{ 265 "handler_name": handlerName, 266 "topic": subscribeTopic, 267 }) 268 269 r.handlersLock.Lock() 270 defer r.handlersLock.Unlock() 271 272 if _, ok := r.handlers[handlerName]; ok { 273 panic(DuplicateHandlerNameError{handlerName}) 274 } 275 276 publisherName, subscriberName := pkg.StructName(publisher), pkg.StructName(subscriber) 277 278 newHandler := &handler{ 279 name: handlerName, 280 logger: r.logger, 281 282 subscriber: subscriber, 283 subscribeTopic: subscribeTopic, 284 subscriberName: subscriberName, 285 286 publisher: publisher, 287 publishTopic: publishTopic, 288 publisherName: publisherName, 289 290 handlerFunc: handlerFunc, 291 292 runningHandlersWg: r.runningHandlersWg, 293 294 messagesCh: nil, 295 routersCloseCh: r.ClosingInProgressCh, 296 297 startedCh: make(chan struct{}), 298 } 299 300 r.handlersWg.Add(1) 301 r.handlers[handlerName] = newHandler 302 303 select { 304 case r.handlerAdded <- struct{}{}: 305 default: 306 // closeWhenAllHandlersStopped is not always waiting for handlerAdded 307 } 308 309 return &Handler{ 310 router: r, 311 handler: newHandler, 312 } 313 } 314 315 // AddNoPublisherHandler adds a new handler. 316 // This handler cannot return messages. 317 // When message is returned it will occur an error and Nack will be sent. 318 // 319 // handlerName must be unique. For now, it is used only for debugging. 320 // 321 // subscribeTopic is a topic from which handler will receive messages. 322 // 323 // subscriber is Subscriber from which messages will be consumed. 324 // 325 // If handler is added while router is already running, you need to explicitly call RunHandlers(). 326 func (r *Router) AddNoPublisherHandler( 327 handlerName string, 328 subscribeTopic string, 329 subscriber Subscriber, 330 handlerFunc NoPublishHandlerFunc, 331 ) *Handler { 332 handlerFuncAdapter := func(msg *Message) ([]*Message, error) { 333 return nil, handlerFunc(msg) 334 } 335 336 return r.AddHandler(handlerName, subscribeTopic, subscriber, "", disabledPublisher{}, handlerFuncAdapter) 337 } 338 339 // Run runs all plugins and handlers and starts subscribing to provided topics. 340 // This call is blocking while the router is running. 341 // 342 // When all handlers have stopped (for example, because subscriptions were closed), the router will also stop. 343 // 344 // To stop Run() you should call Close() on the router. 345 // 346 // ctx will be propagated to all subscribers. 347 // 348 // When all handlers are stopped (for example: because of closed connection), Run() will be also stopped. 349 func (r *Router) Run(ctx context.Context) (err error) { 350 if r.isRunning { 351 return ErrRouterIsAlreadyRunning 352 } 353 r.isRunning = true 354 355 ctx, cancel := context.WithCancel(ctx) 356 defer cancel() 357 358 r.logger.Debug("[Common] watermill loading plugins", nil) 359 for _, plugin := range r.plugins { 360 if err := plugin(r); err != nil { 361 return errors.Wrapf(err, "cannot initialize plugin %v", plugin) 362 } 363 } 364 365 if err := r.RunHandlers(ctx); err != nil { 366 return err 367 } 368 369 close(r.running) 370 371 go r.closeWhenAllHandlersStopped(ctx) 372 373 <-r.ClosingInProgressCh 374 cancel() 375 376 r.logger.Info("[Common] watermill waiting for messages", watermill.LogFields{ 377 "timeout": r.config.CloseTimeout, 378 }) 379 380 <-r.ClosedCh 381 382 r.logger.Info("[Common] watermill all messages processed", nil) 383 384 return nil 385 } 386 387 // RunHandlers runs all handlers that were added after Run(). 388 // RunHandlers is idempotent, so can be called multiple times safely. 389 func (r *Router) RunHandlers(ctx context.Context) error { 390 if !r.isRunning { 391 return errors.New("you can't call RunHandlers on non-running router") 392 } 393 394 r.handlersLock.Lock() 395 defer r.handlersLock.Unlock() 396 397 r.logger.Info("[Common] watermill running router handlers", watermill.LogFields{"count": len(r.handlers)}) 398 399 for name, h := range r.handlers { 400 name := name 401 h := h 402 403 if h.started { 404 continue 405 } 406 407 if err := r.decorateHandlerPublisher(h); err != nil { 408 return errors.Wrapf(err, "could not decorate publisher of handler %s", name) 409 } 410 if err := r.decorateHandlerSubscriber(h); err != nil { 411 return errors.Wrapf(err, "could not decorate subscriber of handler %s", name) 412 } 413 414 r.logger.Debug("[Common] watermill subscribing to topic", watermill.LogFields{ 415 "subscriber_name": h.name, 416 "topic": h.subscribeTopic, 417 }) 418 419 ctx, cancel := context.WithCancel(ctx) 420 421 messages, err := h.subscriber.Subscribe(ctx, h.subscribeTopic) 422 if err != nil { 423 cancel() 424 return errors.Wrapf(err, "cannot subscribe topic %s", h.subscribeTopic) 425 } 426 427 h.messagesCh = messages 428 h.started = true 429 close(h.startedCh) 430 431 h.stopFn = cancel 432 h.stopped = make(chan struct{}) 433 434 go func() { 435 defer cancel() 436 437 h.run(ctx, r.middlewares) 438 439 r.handlersWg.Done() 440 r.logger.Info("[Common] watermill subscriber stopped", watermill.LogFields{ 441 "subscriber_name": h.name, 442 "topic": h.subscribeTopic, 443 }) 444 445 r.handlersLock.Lock() 446 delete(r.handlers, name) 447 r.handlersLock.Unlock() 448 }() 449 } 450 return nil 451 } 452 453 // closeWhenAllHandlersStopped closed router, when all handlers has stopped, 454 // because for example all subscriptions are closed. 455 func (r *Router) closeWhenAllHandlersStopped(ctx context.Context) { 456 r.handlersLock.RLock() 457 hasHandlers := len(r.handlers) == 0 458 r.handlersLock.RUnlock() 459 460 if hasHandlers { 461 // in that situation router will be closed immediately (even if they are no routers) 462 // let's wait for 463 select { 464 case <-r.handlerAdded: 465 // it should be some handler to track 466 case <-r.ClosedCh: 467 // let's avoid goroutine leak 468 return 469 } 470 } 471 472 r.handlersWg.Wait() 473 if r.IsClosed() { 474 // already closed 475 return 476 } 477 478 // Only log an error if the context was not canceled, but handlers were stopped. 479 select { 480 case <-ctx.Done(): 481 default: 482 r.logger.Error("[Common] watermill all handlers stopped, closing router", 483 errors.New("all router handlers stopped"), nil) 484 } 485 486 if err := r.Close(); err != nil { 487 r.logger.Error("[Common] watermill cannot close router", err, nil) 488 } 489 } 490 491 // Running is closed when router is running. 492 // In other words: you can wait till router is running using 493 // 494 // fmt.Println("Starting router") 495 // go r.Run(ctx) 496 // <- r.Running() 497 // fmt.Println("Router is running") 498 // 499 // Warning: for historical reasons, this channel is not aware of router closing - 500 // the channel will be closed if the router has been running and closed. 501 func (r *Router) Running() chan struct{} { 502 return r.running 503 } 504 505 // IsRunning returns true when router is running. 506 // 507 // Warning: for historical reasons, this method is not aware of router closing. 508 // If you want to know if the router was closed, use IsClosed. 509 func (r *Router) IsRunning() bool { 510 select { 511 case <-r.running: 512 return true 513 default: 514 return false 515 } 516 } 517 518 // Close gracefully closes the router with a timeout provided in the configuration. 519 func (r *Router) Close() error { 520 r.closedLock.Lock() 521 defer r.closedLock.Unlock() 522 523 r.handlersLock.Lock() 524 defer r.handlersLock.Unlock() 525 526 if r.closed { 527 return nil 528 } 529 r.closed = true 530 531 r.logger.Info("[Common] watermill closing router", nil) 532 defer r.logger.Info("[Common] watermill router closed", nil) 533 534 close(r.ClosingInProgressCh) 535 defer close(r.ClosedCh) 536 537 timeouted := r.waitForHandlers() 538 if timeouted { 539 return errors.New("router close timeout") 540 } 541 542 return nil 543 } 544 545 func (r *Router) waitForHandlers() bool { 546 var waitGroup sync.WaitGroup 547 waitGroup.Add(1) 548 go func() { 549 defer waitGroup.Done() 550 r.handlersWg.Wait() 551 }() 552 waitGroup.Add(1) 553 go func() { 554 defer waitGroup.Done() 555 556 r.runningHandlersWg.Wait() 557 }() 558 return utils.Timeout(r.config.CloseTimeout, utils.TimeoutWg(&waitGroup)) 559 } 560 561 func (r *Router) IsClosed() bool { 562 r.closedLock.Lock() 563 defer r.closedLock.Unlock() 564 565 return r.closed 566 } 567 568 type handler struct { 569 name string 570 logger watermill.LoggerAdapter 571 572 subscriber Subscriber 573 subscribeTopic string 574 subscriberName string 575 576 publisher Publisher 577 publishTopic string 578 publisherName string 579 580 handlerFunc HandlerFunc 581 582 runningHandlersWg *sync.WaitGroup 583 584 messagesCh <-chan *Message 585 586 started bool 587 startedCh chan struct{} 588 589 stopFn context.CancelFunc 590 stopped chan struct{} 591 routersCloseCh chan struct{} 592 } 593 594 func (h *handler) run(ctx context.Context, middlewares []middleware) { 595 h.logger.Info("[Common] watermill starting handler", watermill.LogFields{ 596 "subscriber_name": h.name, 597 "topic": h.subscribeTopic, 598 }) 599 600 middlewareHandler := h.handlerFunc 601 // first added middlewares should be executed first (so should be at the top of call stack) 602 for i := len(middlewares) - 1; i >= 0; i-- { 603 currentMiddleware := middlewares[i] 604 isValidHandlerLevelMiddleware := currentMiddleware.HandlerName == h.name 605 if currentMiddleware.IsRouterLevel || isValidHandlerLevelMiddleware { 606 middlewareHandler = currentMiddleware.Handler(middlewareHandler) 607 } 608 } 609 610 go h.handleClose(ctx) 611 612 for msg := range h.messagesCh { 613 h.runningHandlersWg.Add(1) 614 go h.handleMessage(msg, middlewareHandler) 615 } 616 617 if h.publisher != nil { 618 h.logger.Debug("[Common] watermill waiting for publisher to close", nil) 619 if err := h.publisher.Close(); err != nil { 620 h.logger.Error("[Common] watermill failed to close publisher", err, nil) 621 } 622 h.logger.Debug("[Common] watermill publisher closed", nil) 623 } 624 625 h.logger.Debug("[Common] watermill router handler stopped", nil) 626 close(h.stopped) 627 } 628 629 // Handler handles Messages. 630 type Handler struct { 631 router *Router 632 handler *handler 633 } 634 635 // AddMiddleware adds new middleware to the specified handler in the router. 636 // 637 // The order of middleware matters. Middleware added at the beginning is executed first. 638 func (h *Handler) AddMiddleware(m ...HandlerMiddleware) { 639 handler := h.handler 640 handler.logger.Debug("[Common] watermill adding middleware to handler", watermill.LogFields{ 641 "count": fmt.Sprintf("%d", len(m)), 642 "handlerName": handler.name, 643 }) 644 645 h.router.addHandlerLevelMiddleware(handler.name, m...) 646 } 647 648 // Started returns channel which is stopped when handler is running. 649 func (h *Handler) Started() chan struct{} { 650 return h.handler.startedCh 651 } 652 653 // Stop stops the handler. 654 // Stop is asynchronous. 655 // You can check if handler was stopped with Stopped() function. 656 func (h *Handler) Stop() { 657 if !h.handler.started { 658 panic("handler is not started") 659 } 660 661 h.handler.stopFn() 662 } 663 664 // Stopped returns channel which is stopped when handler did stop. 665 func (h *Handler) Stopped() chan struct{} { 666 return h.handler.stopped 667 } 668 669 // decorateHandlerPublisher applies the decorator chain to handler's publisher. 670 // They are applied in reverse order, so that the later decorators use the result of former ones. 671 func (r *Router) decorateHandlerPublisher(h *handler) error { 672 var err error 673 pub := h.publisher 674 for i := len(r.publisherDecorators) - 1; i >= 0; i-- { 675 decorator := r.publisherDecorators[i] 676 pub, err = decorator(pub) 677 if err != nil { 678 return errors.Wrap(err, "could not apply publisher decorator") 679 } 680 } 681 r.handlers[h.name].publisher = pub 682 return nil 683 } 684 685 // decorateHandlerSubscriber applies the decorator chain to handler's subscriber. 686 // They are applied in regular order, so that the later decorators use the result of former ones. 687 func (r *Router) decorateHandlerSubscriber(h *handler) error { 688 var err error 689 sub := h.subscriber 690 691 // add values to message context to subscriber 692 // it goes before other decorators, so that they may take advantage of these values 693 messageTransform := func(msg *Message) { 694 if msg != nil { 695 h.addHandlerContext(msg) 696 } 697 } 698 sub, err = MessageTransformSubscriberDecorator(messageTransform)(sub) 699 if err != nil { 700 return errors.Wrapf(err, "cannot wrap subscriber with context decorator") 701 } 702 703 for _, decorator := range r.subscriberDecorators { 704 sub, err = decorator(sub) 705 if err != nil { 706 return errors.Wrap(err, "could not apply subscriber decorator") 707 } 708 } 709 r.handlers[h.name].subscriber = sub 710 return nil 711 } 712 713 // addHandlerContext enriches the contex with values that are relevant within this handler's context. 714 func (h *handler) addHandlerContext(messages ...*Message) { 715 for i, msg := range messages { 716 ctx := msg.Context() 717 718 if h.name != "" { 719 ctx = context.WithValue(ctx, handlerNameKey, h.name) 720 } 721 if h.publisherName != "" { 722 ctx = context.WithValue(ctx, publisherNameKey, h.publisherName) 723 } 724 if h.subscriberName != "" { 725 ctx = context.WithValue(ctx, subscriberNameKey, h.subscriberName) 726 } 727 if h.subscribeTopic != "" { 728 ctx = context.WithValue(ctx, subscribeTopicKey, h.subscribeTopic) 729 } 730 if h.publishTopic != "" { 731 ctx = context.WithValue(ctx, publishTopicKey, h.publishTopic) 732 } 733 messages[i].SetContext(ctx) 734 } 735 } 736 737 func (h *handler) handleClose(ctx context.Context) { 738 select { 739 case <-h.routersCloseCh: 740 // for backward compatibility we are closing subscriber 741 h.logger.Debug("[Common] watermill waiting for subscriber to close", nil) 742 if err := h.subscriber.Close(); err != nil { 743 h.logger.Error("[Common] watermill failed to close subscriber", err, nil) 744 } 745 h.logger.Debug("[Common] watermill subscriber closed", nil) 746 case <-ctx.Done(): 747 // we are closing subscriber just when entire router is closed 748 } 749 h.stopFn() 750 } 751 752 func (h *handler) handleMessage(msg *Message, handler HandlerFunc) { 753 defer h.runningHandlersWg.Done() 754 msgFields := watermill.LogFields{"message_uuid": msg.UUID} 755 756 defer func() { 757 if recovered := recover(); recovered != nil { 758 h.logger.Error( 759 "[Common] watermill panic recovered in handler. Stack: "+string(debug.Stack()), 760 errors.Errorf("%s", recovered), 761 msgFields, 762 ) 763 msg.Nack() 764 } 765 }() 766 767 h.logger.Trace("[Common] watermill received message", msgFields) 768 769 producedMessages, err := handler(msg) 770 if err != nil { 771 h.logger.Error("[Common] watermill handler returned error", err, nil) 772 msg.Nack() 773 return 774 } 775 776 // ack & nack by business for non-router calling 777 disableAck := false 778 if len(producedMessages) > 0 { 779 for i, msg := range producedMessages { 780 if _, disableAck = msg.Metadata[watermill.MessageRouterAck]; disableAck { 781 producedMessages = append(producedMessages[0:i], producedMessages[i+1:]...) 782 } 783 } 784 } 785 786 h.addHandlerContext(producedMessages...) 787 788 if err := h.publishProducedMessages(msg.Context(), producedMessages, msgFields); err != nil { 789 h.logger.Error("[Common] watermill publishing produced messages failed", err, nil) 790 if !disableAck { 791 msg.Nack() 792 } else { 793 h.logger.Trace("[Common] watermill message should be nack by business", msgFields) 794 } 795 return 796 } 797 if !disableAck { 798 msg.Ack() 799 h.logger.Trace("[Common] watermill message acked", msgFields) 800 } else { 801 h.logger.Trace("[Common] watermill message should be acked by business", msgFields) 802 } 803 } 804 805 func (h *handler) publishProducedMessages(ctx context.Context, 806 producedMessages Messages, msgFields watermill.LogFields) error { 807 if len(producedMessages) == 0 { 808 return nil 809 } 810 811 if h.publisher == nil { 812 return ErrOutputInNoPublisherHandler 813 } 814 815 h.logger.Trace("Sending produced messages", msgFields.Add(watermill.LogFields{ 816 "produced_messages_count": len(producedMessages), 817 "publish_topic": h.publishTopic, 818 })) 819 820 for _, msg := range producedMessages { 821 if err := h.publisher.Publish(ctx, h.publishTopic, msg); err != nil { 822 // todo - how to deal with it better/transactional/retry? 823 h.logger.Error("Cannot publish message", err, msgFields.Add(watermill.LogFields{ 824 "not_sent_message": fmt.Sprintf("%#v", producedMessages), 825 })) 826 827 return err 828 } 829 } 830 831 return nil 832 } 833 834 type disabledPublisher struct{} 835 836 func (disabledPublisher) Publish(ctx context.Context, topic string, messages ...*Message) error { 837 return ErrOutputInNoPublisherHandler 838 } 839 840 func (disabledPublisher) Close() error { 841 return nil 842 }