mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-09-29 06:19:04 +02:00
Co-authored-by: Alessandro (Ale) Segala <43508+ItalyPaleAle@users.noreply.github.com> Co-authored-by: Elias Schneider <login@eliasschneider.com>
68 lines
2.0 KiB
Go
68 lines
2.0 KiB
Go
package backchannellogout
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
|
|
"github.com/italypaleale/francis/actor"
|
|
)
|
|
|
|
// ActorType is the actor type that delivers back-channel logout tokens as durable jobs
|
|
const ActorType = "BackchannelLogoutNotifier"
|
|
|
|
// methodDeliver is the job method that delivers one logout token to one client
|
|
const methodDeliver = "deliver"
|
|
|
|
const (
|
|
// deliveryConcurrency caps running delivery jobs per host without letting idle actors hold the available capacity
|
|
deliveryConcurrency = 4
|
|
|
|
// deliveryMaxAttempts caps the delivery attempts for one notification, so an unreachable client is not retried forever
|
|
deliveryMaxAttempts = 3
|
|
)
|
|
|
|
// notifierActor delivers the logout tokens scheduled as jobs
|
|
// Jobs make the notifications durable: they survive a restart and failed deliveries are retried up to deliveryMaxAttempts times
|
|
type notifierActor struct {
|
|
service *Service
|
|
}
|
|
|
|
func (s *Service) newNotifierActor(_ string, _ *actor.Service) actor.Actor {
|
|
return ¬ifierActor{service: s}
|
|
}
|
|
|
|
// Job implements actor.ActorJob
|
|
func (a *notifierActor) Job(ctx context.Context, method string, data actor.Envelope) error {
|
|
if method != methodDeliver {
|
|
return fmt.Errorf("%w: unsupported method '%s'", actor.ErrJobPermanentFailure, method)
|
|
}
|
|
if data == nil {
|
|
return fmt.Errorf("%w: job input is empty", actor.ErrJobPermanentFailure)
|
|
}
|
|
|
|
var t target
|
|
err := data.Decode(&t)
|
|
if err != nil {
|
|
return fmt.Errorf("%w: job input is not a valid target: %w", actor.ErrJobPermanentFailure, err)
|
|
}
|
|
|
|
return a.service.sendLogoutToken(ctx, t)
|
|
}
|
|
|
|
// JobFailed implements actor.ActorJobFailed
|
|
func (a *notifierActor) JobFailed(ctx context.Context, _ string, _ string, data actor.Envelope, jobErr error) error {
|
|
var t target
|
|
if data != nil {
|
|
_ = data.Decode(&t)
|
|
}
|
|
|
|
slog.ErrorContext(ctx, "Giving up on delivering back-channel logout token",
|
|
slog.String("clientId", t.ClientID),
|
|
slog.String("userId", t.UserID),
|
|
slog.String("logoutUrl", t.LogoutURL),
|
|
slog.Any("error", jobErr),
|
|
)
|
|
return nil
|
|
}
|