github.com/wfusion/gofusion@v1.1.14/common/infra/watermill/components/requestreply/requestreply.go (about)

     1  package requestreply
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/wfusion/gofusion/common/infra/watermill/message"
     9  )
    10  
    11  // NoResult is a result type for commands that don't have result.
    12  type NoResult = struct{}
    13  
    14  type Reply[Result any] struct {
    15  	// HandlerResult contains the handler result.
    16  	// It's preset only when NewCommandHandlerWithResult is used. If NewCommandHandler is used, HandlerResult is empty.
    17  	//
    18  	// Result is sent even if the handler returns an error.
    19  	HandlerResult Result
    20  
    21  	// Error contains the error returned by the command handler or the Backend when handling notification fails.
    22  	// Handling the notification can fail, for example, when unmarshaling the message or if there's a timeout.
    23  	// If listening for a reply times out or the context is canceled, the Error is ReplyTimeoutError.
    24  	//
    25  	// If an error from the handler is returned, CommandHandlerError is returned.
    26  	// If processing was successful, Error is nil.
    27  	Error error
    28  
    29  	// NotificationMessage contains the notification message sent after the command is handled.
    30  	// It's present only if the request/reply backend uses a Pub/Sub for notifications (for example, PubSubBackend).
    31  	//
    32  	// Warning: NotificationMessage is nil if a timeout occurs.
    33  	NotificationMessage *message.Message
    34  }
    35  
    36  type Backend[Result any] interface {
    37  	ListenForNotifications(ctx context.Context, params BackendListenForNotificationsParams) (<-chan Reply[Result], error)
    38  	OnCommandProcessed(ctx context.Context, params BackendOnCommandProcessedParams[Result]) error
    39  }
    40  
    41  type BackendListenForNotificationsParams struct {
    42  	Command     any
    43  	OperationID OperationID
    44  }
    45  
    46  type BackendOnCommandProcessedParams[Result any] struct {
    47  	Command        any
    48  	CommandMessage *message.Message
    49  
    50  	HandlerResult Result
    51  	HandleErr     error
    52  }
    53  
    54  // OperationID is a unique identifier of a command.
    55  // It correlates commands with replies between the bus and the handler.
    56  type OperationID string
    57  
    58  // ReplyTimeoutError is returned when the reply timeout is exceeded.
    59  type ReplyTimeoutError struct {
    60  	Duration time.Duration
    61  	Err      error
    62  }
    63  
    64  func (e ReplyTimeoutError) Error() string {
    65  	return fmt.Sprintf("reply timeout after %s: %s", e.Duration, e.Err)
    66  }
    67  
    68  type ReplyUnmarshalError struct {
    69  	Err error
    70  }
    71  
    72  func (r ReplyUnmarshalError) Error() string {
    73  	return fmt.Sprintf("cannot unmarshal reply: %s", r.Err)
    74  }
    75  
    76  func (r ReplyUnmarshalError) Unwrap() error {
    77  	return r.Err
    78  }
    79  
    80  // CommandHandlerError is returned when the command handler returns an error.
    81  type CommandHandlerError struct {
    82  	Err error
    83  }
    84  
    85  func (e CommandHandlerError) Error() string {
    86  	return e.Err.Error()
    87  }
    88  
    89  func (e CommandHandlerError) Unwrap() error {
    90  	return e.Err
    91  }