|
1 | | -package events |
2 | | - |
3 | | -import ( |
4 | | - "context" |
5 | | - "log/slog" |
6 | | - "strconv" |
7 | | - "time" |
8 | | - |
9 | | - "github.com/database-playground/backend-v2/ent" |
10 | | - "github.com/posthog/posthog-go" |
11 | | - "go.opentelemetry.io/otel" |
12 | | - "go.opentelemetry.io/otel/attribute" |
13 | | - otelcodes "go.opentelemetry.io/otel/codes" |
14 | | - "go.opentelemetry.io/otel/trace" |
15 | | -) |
16 | | - |
17 | | -var tracer = otel.Tracer("dbplay.events") |
18 | | - |
19 | | -// EventService is the service for triggering events. |
20 | | -type EventService struct { |
21 | | - entClient *ent.Client |
22 | | - posthogClient posthog.Client |
23 | | - |
24 | | - handlers []EventHandler |
25 | | -} |
26 | | - |
27 | | -// NewEventService creates a new EventService. |
28 | | -func NewEventService(entClient *ent.Client, posthogClient posthog.Client) *EventService { |
29 | | - return &EventService{ |
30 | | - entClient: entClient, |
31 | | - posthogClient: posthogClient, |
32 | | - handlers: []EventHandler{NewPointsGranter(entClient, posthogClient)}, |
33 | | - } |
34 | | -} |
35 | | - |
36 | | -// Event is the event to be triggered. |
37 | | -type Event struct { |
38 | | - Type EventType |
39 | | - Payload map[string]any |
40 | | - UserID int |
41 | | -} |
42 | | - |
43 | | -// EventHandler is the handler for the event. |
44 | | -// |
45 | | -// You can think it as the callback of the event. |
46 | | -type EventHandler interface { |
47 | | - HandleEvent(ctx context.Context, event *ent.Event) error |
48 | | -} |
49 | | - |
50 | | -// TriggerEvent triggers an event. |
51 | | -func (s *EventService) TriggerEvent(ctx context.Context, event Event) { |
52 | | - ctx, span := tracer.Start(ctx, "TriggerEvent", |
53 | | - trace.WithAttributes( |
54 | | - attribute.String("event.type", string(event.Type)), |
55 | | - attribute.Int("user.id", event.UserID), |
56 | | - )) |
57 | | - defer span.End() |
58 | | - |
59 | | - err := s.triggerEvent(ctx, event) |
60 | | - if err != nil { |
61 | | - span.SetStatus(otelcodes.Error, "Failed to trigger event") |
62 | | - span.RecordError(err) |
63 | | - slog.Error("failed to trigger event", "error", err) |
64 | | - } else { |
65 | | - span.SetStatus(otelcodes.Ok, "Event triggered successfully") |
66 | | - } |
67 | | - |
68 | | - if s.posthogClient != nil { |
69 | | - span.AddEvent("posthog.send", trace.WithAttributes( |
70 | | - attribute.String("event.type", string(event.Type)), |
71 | | - attribute.Int("user.id", event.UserID), |
72 | | - )) |
73 | | - slog.Debug("sending event to PostHog", "event_type", event.Type, "user_id", event.UserID) |
74 | | - err = s.posthogClient.Enqueue(posthog.Capture{ |
75 | | - DistinctId: strconv.Itoa(event.UserID), |
76 | | - Event: string(event.Type), |
77 | | - Timestamp: time.Now(), |
78 | | - Properties: event.Payload, |
79 | | - }) |
80 | | - if err != nil { |
81 | | - span.RecordError(err) |
82 | | - slog.Error("failed to send event to PostHog", "error", err) |
83 | | - } |
84 | | - } |
85 | | -} |
86 | | - |
87 | | -// triggerEvent triggers an event synchronously. |
88 | | -func (s *EventService) triggerEvent(ctx context.Context, event Event) error { |
89 | | - ctx, span := tracer.Start(ctx, "triggerEvent", |
90 | | - trace.WithAttributes( |
91 | | - attribute.String("event.type", string(event.Type)), |
92 | | - attribute.Int("user.id", event.UserID), |
93 | | - )) |
94 | | - defer span.End() |
95 | | - |
96 | | - span.AddEvent("database.event.create") |
97 | | - eventEntity, err := s.entClient.Event.Create(). |
98 | | - SetType(string(event.Type)). |
99 | | - SetPayload(event.Payload). |
100 | | - SetUserID(event.UserID). |
101 | | - SetTriggeredAt(time.Now()). |
102 | | - Save(ctx) |
103 | | - if err != nil { |
104 | | - span.SetStatus(otelcodes.Error, "Failed to create event") |
105 | | - span.RecordError(err) |
106 | | - return err |
107 | | - } |
108 | | - |
109 | | - span.SetAttributes(attribute.Int("event.id", eventEntity.ID)) |
110 | | - span.AddEvent("handlers.processing", trace.WithAttributes( |
111 | | - attribute.Int("handlers.count", len(s.handlers)), |
112 | | - )) |
113 | | - |
114 | | - for i, handler := range s.handlers { |
115 | | - span.AddEvent("handler.executing", trace.WithAttributes( |
116 | | - attribute.Int("handler.index", i), |
117 | | - )) |
118 | | - err := handler.HandleEvent(ctx, eventEntity) |
119 | | - if err != nil { |
120 | | - span.SetStatus(otelcodes.Error, "Failed to handle event") |
121 | | - span.RecordError(err) |
122 | | - return err |
123 | | - } |
124 | | - } |
125 | | - |
126 | | - span.SetStatus(otelcodes.Ok, "Event triggered successfully") |
127 | | - return nil |
128 | | -} |
0 commit comments