Versions in this module Expand all Collapse all v0 v0.1.0 Jul 31, 2026 Changes in this version + const DefaultDLQCollection + const TopicMessageFailed + const TopicMessageSent + var ErrBackendUnavailable = errors.New("grpop: backend unavailable") + var ErrCircuitOpen = errors.New("grpop: circuit breaker is open") + var ErrClosed = errors.New("grpop: closed") + var ErrDLQEventNotClaimed = errors.New("grpop: dead-letter event is not in a claimed (retrying) state") + var ErrDLQEventNotFound = errors.New("grpop: dead-letter event not found") + var ErrEmailFromRequired = errors.New(...) + var ErrEmailTemplateEngineRequired = errors.New(...) + var ErrEmailTemplateNotFound = errors.New("grpop: email template not found") + var ErrIdempotencyKeyRequired = errors.New("grpop: idempotency key is required") + var ErrInlineTemplateTooLarge = errors.New("grpop: inline template exceeds maximum size") + var ErrMultipleContentModesSet = errors.New(...) + var ErrNoContentModeSet = errors.New(...) + var ErrRateLimited = errors.New("grpop: rate limited") + var ErrRecipientRequired = errors.New("grpop: recipient is required") + var ErrTooManyRequests = errors.New("grpop: too many requests while circuit breaker is half-open") + var ErrWhatsAppLanguageCodeRequired = errors.New("grpop: whatsapp language code is required") + var ErrWhatsAppTemplateArityMismatch = errors.New(...) + var ErrWhatsAppTemplateNameRequired = errors.New("grpop: whatsapp template name is required") + var ErrWhatsAppTemplateNotApproved = errors.New("grpop: whatsapp template is not approved") + var Version = "v0.1.0" + func FullJitterBackoff(base, max time.Duration, attempt int) time.Duration + func PublishMessageFailed(ctx context.Context, bus grevents.Bus, logger Logger, ...) + func PublishMessageSent(ctx context.Context, bus grevents.Bus, logger Logger, ...) + type Channel string + const ChannelEmail + const ChannelWhatsApp + type CircuitBreaker interface + Execute func(ctx context.Context, fn func() error) error + GetStats func() CircuitBreakerStats + Reset func() + State func() CircuitState + func NewCircuitBreaker(maxFailures int, timeout, resetTimeout time.Duration) (CircuitBreaker, error) + func NewCircuitBreakerWithConfig(config CircuitBreakerConfig) (CircuitBreaker, error) + type CircuitBreakerConfig struct + Logger Logger + MaxFailures int + MaxHalfOpenRequests int + ResetTimeout time.Duration + Timeout time.Duration + type CircuitBreakerStats struct + ConsecutiveFailures int + LastFailureTime time.Time + LastStateChange time.Time + OpenedAt time.Time + State CircuitState + TimeUntilNextAttempt time.Duration + TotalFailures int64 + TotalRejections int64 + TotalSuccesses int64 + type CircuitState string + const CircuitStateClosed + const CircuitStateHalfOpen + const CircuitStateOpen + type DLQEvent struct + AttemptHistory []DLQRetryAttempt + CreatedAt time.Time + FailureReason string + FirstFailureAt time.Time + LastAttemptAt time.Time + MaxRetries int + MessageData DLQMessage + NextRetryAt time.Time + RetryCount int + SendID string + Status DLQStatus + UpdatedAt time.Time + type DLQHandler interface + ClaimRetryableEvents func(ctx context.Context, limit int) ([]*DLQEvent, error) + Close func() error + GetEventByID func(ctx context.Context, sendID string) (*DLQEvent, error) + MarkRetried func(ctx context.Context, sendID string, success bool, attemptErr error) error + PublishToDLQ func(ctx context.Context, sendID string, msg DLQMessage, failureReason string) error + PurgeExpiredEvents func(ctx context.Context, maxAge time.Duration) (int64, error) + func NewMemoryDLQHandler(maxRetries int, retryDelay, maxRetryDelay time.Duration, maxAttemptHistory int) DLQHandler + func NewMongoDLQHandler(cfg MongoDLQHandlerConfig) (DLQHandler, error) + func NewPostgresDLQHandler(cfg PostgresDLQHandlerConfig) (DLQHandler, error) + type DLQMessage struct + Channel Channel + Email *EmailMessage + ExpiresAt time.Time + WhatsApp *WhatsAppMessage + type DLQRetryAttempt struct + AttemptNumber int + AttemptedAt time.Time + ErrorMessage string + Success bool + type DLQStatus string + const DLQStatusExhausted + const DLQStatusExpired + const DLQStatusPending + const DLQStatusResolved + const DLQStatusRetrying + type EmailMessage struct + From string + HTMLBody string + InlineTemplate *EmailTemplate + ReplyTo string + Subject string + TemplateData map[string]any + TemplateName string + TextBody string + To string + type EmailSender interface + Close func() error + Send func(ctx context.Context, msg EmailMessage) (SendResult, error) + func NewDryRunEmailSender(logger Logger) EmailSender + func NewSMTPDispatcher(deps SMTPDispatcherDeps) (EmailSender, error) + type EmailTemplate struct + HTMLBodyTemplate string + SubjectTemplate string + TextBodyTemplate string + type EmailTemplateEngine interface + RegisterTemplate func(name string, tmpl EmailTemplate) error + Render func(name string, data map[string]any) (subject, htmlBody, textBody string, err error) + RenderInline func(tmpl EmailTemplate, data map[string]any) (subject, htmlBody, textBody string, err error) + func NewEmailTemplateEngine(config EmailTemplateEngineConfig) EmailTemplateEngine + type EmailTemplateEngineConfig struct + MaxInlineTemplateBytes int + type IdempotencyStore interface + Close func() error + IsProcessed func(ctx context.Context, idempotencyKey string) (bool, error) + MarkProcessed func(ctx context.Context, idempotencyKey string, ttl time.Duration) error + func NewCacheIdempotencyStore(cache grcache.Cache) IdempotencyStore + type Logger interface + Debug func(msg string, args ...any) + Error func(msg string, args ...any) + Info func(msg string, args ...any) + Warn func(msg string, args ...any) + func NopLogger() Logger + func OrNop(l Logger) Logger + type MemoryEmailSender struct + func NewMemoryEmailSender() *MemoryEmailSender + func (s *MemoryEmailSender) Close() error + func (s *MemoryEmailSender) Send(ctx context.Context, msg EmailMessage) (SendResult, error) + func (s *MemoryEmailSender) Sent() []EmailMessage + type MemoryWhatsAppSender struct + func NewMemoryWhatsAppSender() *MemoryWhatsAppSender + func (s *MemoryWhatsAppSender) Close() error + func (s *MemoryWhatsAppSender) Send(ctx context.Context, msg WhatsAppMessage) (SendResult, error) + func (s *MemoryWhatsAppSender) Sent() []WhatsAppMessage + type MessageEncryptor interface + Decrypt func(ciphertext []byte) ([]byte, error) + Encrypt func(plaintext []byte) ([]byte, error) + type MessageFailedPayload struct + Channel Channel + Reason string + SendID string + Timestamp time.Time + type MessageSentPayload struct + Channel Channel + ProviderMessageID string + SendID string + Timestamp time.Time + type MetaCloudDispatcherDeps struct + AccessToken string + BusinessAccountID string + CircuitBreaker CircuitBreaker + Client WhatsAppCloudAPIClient + Logger Logger + Metrics Metrics + PhoneNumberID string + RateLimiter RateLimiter + RequestTimeout time.Duration + TemplateValidator TemplateValidator + type MetaTemplateValidatorDeps struct + Client WhatsAppCloudAPIClient + Logger Logger + TTL time.Duration + type Metrics interface + IncCircuitBreakerStateChange func(channel Channel, newState string) + IncDLQPublished func(channel Channel) + IncIdempotencyDedupHit func(channel Channel) + IncRateLimitRejected func(channel Channel) + IncSendResult func(channel Channel, status SendStatus) + ObserveSMTPResponseCode func(code int) + ObserveSendLatency func(channel Channel, duration time.Duration) + type MongoDLQHandlerConfig struct + CollectionName string + Database string + Encryptor MessageEncryptor + Logger Logger + MaxAttemptHistoryEntries int + MaxRetries int + MaxRetryDelay time.Duration + RetryDelay time.Duration + URI string + type PostgresConfig struct + ConnectTimeout time.Duration + DSN string + Logger Logger + MaxConnLifetime time.Duration + MaxConns int32 + MinConns int32 + Pool *pgxpool.Pool + SkipSchemaEnsure bool + type PostgresDLQHandlerConfig struct + Encryptor MessageEncryptor + MaxAttemptHistoryEntries int + MaxRetries int + MaxRetryDelay time.Duration + RetryDelay time.Duration + type RateLimiter interface + Allow func(ctx context.Context, channel Channel, recipient string) (bool, error) + GetStats func(ctx context.Context, channel Channel, recipient string) (RateLimiterStats, error) + Wait func(ctx context.Context, channel Channel, recipient string) error + func NewLocalRateLimiter(requestsPerSecond, burstSize, recipientCacheSize int) (RateLimiter, error) + func NewRedisRateLimiter(cfg RedisRateLimiterConfig) (RateLimiter, error) + type RateLimiterStats struct + AllowedCount int64 + BlockedCount int64 + BurstSize int + LastAllowedAt time.Time + RequestsPerSecond int + WaitCount int64 + type RedisRateLimiterConfig struct + Addr string + BurstSize int + DB int + DialTimeout time.Duration + KeyPrefix string + Logger Logger + Password string + PoolSize int + ReadTimeout time.Duration + RequestsPerSecond int + WriteTimeout time.Duration + type SMTPClient interface + Auth func(a smtp.Auth) error + Close func() error + Data func() (io.WriteCloser, error) + Mail func(from string) error + Rcpt func(to string) error + type SMTPDialer interface + Dial func(addr string) (SMTPClient, error) + type SMTPDispatcherDeps struct + Addr string + AllowInsecureAuth bool + Auth smtp.Auth + CircuitBreaker CircuitBreaker + ConnectTimeout time.Duration + DefaultFrom string + Dialer SMTPDialer + Logger Logger + Metrics Metrics + RateLimiter RateLimiter + SendTimeout time.Duration + TLSMode SMTPTLSMode + TemplateEngine EmailTemplateEngine + type SMTPTLSMode string + const SMTPTLSImplicit + const SMTPTLSInsecureNoTLS + const SMTPTLSStartTLS + type SendOptions struct + IdempotencyKey string + IdempotencyTTL time.Duration + RetryExpiresAt time.Time + SkipRateLimit bool + type SendResult struct + Channel Channel + Duplicate bool + ProviderMessageID string + Raw map[string]string + SentAt time.Time + Status SendStatus + type SendStatus string + const SendStatusFailed + const SendStatusSent + type Service interface + Close func() error + SendEmail func(ctx context.Context, msg EmailMessage, opts SendOptions) (SendResult, error) + SendWhatsApp func(ctx context.Context, msg WhatsAppMessage, opts SendOptions) (SendResult, error) + func NewService(deps ServiceDeps) (Service, error) + type ServiceConfig struct + DefaultIdempotencyTTL time.Duration + DefaultMaxRetryAge time.Duration + InlineRetryBaseDelay time.Duration + InlineRetryMaxDelay time.Duration + MaxInlineRetries int + func DefaultServiceConfig() ServiceConfig + type ServiceDeps struct + Config ServiceConfig + DLQHandler DLQHandler + EmailSender EmailSender + EventBus grevents.Bus + IdempotencyStore IdempotencyStore + Logger Logger + Metrics Metrics + WhatsAppSender WhatsAppSender + type TemplateValidator interface + Refresh func(ctx context.Context) error + Validate func(ctx context.Context, templateName, languageCode string, ...) error + func NewMetaTemplateValidator(deps MetaTemplateValidatorDeps) (TemplateValidator, error) + type WhatsAppCloudAPIClient interface + GetApprovedTemplates func(ctx context.Context) ([]WhatsAppTemplateInfo, error) + SendTemplateMessage func(ctx context.Context, req WhatsAppCloudAPIRequest) (WhatsAppCloudAPIResponse, error) + type WhatsAppCloudAPIRequest struct + LanguageCode string + TemplateName string + TemplateVariables map[string]string + To string + type WhatsAppCloudAPIResponse struct + MessageID string + type WhatsAppMessage struct + LanguageCode string + TemplateName string + TemplateVariables map[string]string + To string + type WhatsAppSender interface + Close func() error + Send func(ctx context.Context, msg WhatsAppMessage) (SendResult, error) + func NewDryRunWhatsAppSender(logger Logger) WhatsAppSender + func NewMetaCloudWhatsAppDispatcher(deps MetaCloudDispatcherDeps) (WhatsAppSender, error) + type WhatsAppTemplateInfo struct + LanguageCode string + Name string + ParameterCount int