Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
abacda3
feat: add manual DSM injection for event bridge publishing
jeastham1993 Feb 25, 2026
05ca0b9
fix: update event bridge source
jeastham1993 Feb 25, 2026
c35934a
fix: resolve build error
jeastham1993 Feb 25, 2026
74692fe
feat: update API of printjob completed event
jeastham1993 Feb 25, 2026
7c417cd
feat: implement sticker printed handling
jeastham1993 Feb 25, 2026
4c34975
feat: update IaC to map print completed
jeastham1993 Feb 25, 2026
82538a2
chore: replace automated CLaude review with Codex
jeastham1993 Feb 25, 2026
3d9057f
chore: fix PR feedback and handle cloud events
jeastham1993 Feb 25, 2026
0232247
fix: fix print service build error
jeastham1993 Feb 25, 2026
6a0e4d7
fix: use Encoding.UTF8.GetBytes instead of JsonSerializer for CloudEv…
jeastham1993 Feb 25, 2026
127e27f
fix: wrap injected test messages in structured CloudEvents
jeastham1993 Feb 25, 2026
d7c31b6
feat: fix integration test bug
jeastham1993 Feb 25, 2026
5667830
fix: make Kafka consumers long-lived to eliminate rebalance overhead …
jeastham1993 Feb 25, 2026
894fd9c
chore: update event handlers and add transaction tracking
jeastham1993 Mar 3, 2026
01db940
Merge branch 'main' into feat/add-additional-event-handlers
jeastham1993 Mar 3, 2026
254196f
chore: add example of Datadog transaction tracking
jeastham1993 Mar 3, 2026
daa2314
chore: update docker compose for transaction tracking
jeastham1993 Mar 3, 2026
09ccffb
fix: write DSM-injected headers back to JSON before publishing to Eve…
jeastham1993 Mar 3, 2026
70623ca
chore: update DSM feature enablement
jeastham1993 Mar 3, 2026
19f3eff
fix: register DatadogTransactionTracker and IHttpClientFactory in AWS…
jeastham1993 Mar 3, 2026
ecd11fe
fix: unwrap CloudEvent envelope in ServiceBusStickerClaimedWorker
jeastham1993 Mar 3, 2026
0346c2f
chore: update load sim to auto restart
jeastham1993 Mar 3, 2026
8dff6e9
chore: fix DSM propagation
jeastham1993 Mar 4, 2026
ce1040c
Merge branch 'main' into feat/add-additional-event-handlers
jeastham1993 Mar 4, 2026
d388844
fix: address scottgerring PR review feedback
jeastham1993 Mar 5, 2026
a237e71
chore: fix DSM example in AWS deployment
jeastham1993 Mar 24, 2026
fadd728
fix: address PR review feedback on event workers and tracker duplication
jeastham1993 Mar 27, 2026
148ea84
Merge branch 'main' into feat/add-additional-event-handlers
jeastham1993 Mar 27, 2026
3e01435
fix: skip DD pipeline call when DD_API_KEY is absent and set CloudEve…
jeastham1993 Mar 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 0 additions & 44 deletions .github/workflows/claude-code-review.yml

This file was deleted.

78 changes: 0 additions & 78 deletions .github/workflows/claude-code-review.yml.disabled

This file was deleted.

19 changes: 16 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -379,11 +379,14 @@ services:
condition: service_healthy
environment:
# DataDog APM configuration
DD_API_KEY: ${DD_API_KEY}
Comment thread
scottgerring marked this conversation as resolved.
DD_SITE: ${DD_SITE:-datadoghq.com}
DD_SERVICE: print-service
DD_ENV: ${ENV:-development}
DD_VERSION: ${COMMIT_SHA:-latest}
DD_AGENT_HOST: datadog-agent
DD_DATA_STREAMS_ENABLED: "true"
DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED: "true"
Comment thread
jeastham1993 marked this conversation as resolved.
DD_TRACE_OTEL_ENABLED: "true"
DD_LOGS_INJECTION: "true"
DD_RUNTIME_METRICS_ENABLED: "true"
Expand Down Expand Up @@ -433,11 +436,14 @@ services:
condition: service_healthy
environment:
# DataDog APM configuration
DD_API_KEY: ${DD_API_KEY}
DD_SITE: ${DD_SITE:-datadoghq.com}
DD_SERVICE: print-service
DD_ENV: ${ENV:-development}
DD_VERSION: ${COMMIT_SHA:-latest}
DD_AGENT_HOST: datadog-agent
DD_DATA_STREAMS_ENABLED: "true"
DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED: "true"
DD_TRACE_OTEL_ENABLED: "true"
DD_LOGS_INJECTION: "true"
DD_RUNTIME_METRICS_ENABLED: "true"
Expand Down Expand Up @@ -474,11 +480,14 @@ services:
- "8086:8080"
environment:
# DataDog APM configuration
DD_API_KEY: ${DD_API_KEY}
DD_SITE: ${DD_SITE:-datadoghq.com}
DD_SERVICE: print-service-client
DD_ENV: ${ENV:-development}
DD_VERSION: ${COMMIT_SHA:-latest}
DD_AGENT_HOST: datadog-agent
DD_DATA_STREAMS_ENABLED: "true"
DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED: "true"
DD_TRACE_OTEL_ENABLED: "true"
DD_LOGS_INJECTION: "true"
DD_RUNTIME_METRICS_ENABLED: "true"
Expand Down Expand Up @@ -538,7 +547,8 @@ services:
DD_ENV: ${ENV:-development}
DD_VERSION: ${COMMIT_SHA:-latest}
DD_AGENT_HOST: datadog-agent
DD_DATA_STREAMS_ENABLED: true
DD_DATA_STREAMS_ENABLED: "true"
DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED: "true"
DD_TRACE_OTEL_ENABLED: "true"
DD_LOGS_INJECTION: "true"
DD_RUNTIME_METRICS_ENABLED: "true"
Expand Down Expand Up @@ -592,7 +602,8 @@ services:
DD_ENV: ${ENV:-development}
DD_VERSION: ${COMMIT_SHA:-latest}
DD_AGENT_HOST: datadog-agent
DD_DATA_STREAMS_ENABLED: true
DD_DATA_STREAMS_ENABLED: "true"
DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED: "true"
DD_TRACE_OTEL_ENABLED: "true"
DD_LOGS_INJECTION: "true"
DD_RUNTIME_METRICS_ENABLED: "true"
Expand Down Expand Up @@ -716,7 +727,8 @@ services:
DD_ENV: ${ENV:-development}
DD_VERSION: ${COMMIT_SHA:-latest}
DD_AGENT_HOST: datadog-agent
DD_DATA_STREAMS_ENABLED: true
DD_DATA_STREAMS_ENABLED: "true"
DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED: "true"
# Server configuration
SERVER_PORT: 8080

Expand Down Expand Up @@ -768,6 +780,7 @@ services:
# Load testing service - runs k6 load tests against the stack
load-simulator:
image: grafana/k6:latest
restart: always
volumes:
- ./load-tests:/scripts
environment:
Expand Down
16 changes: 16 additions & 0 deletions mise.toml
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,19 @@ docker compose --profile load-test run --rm load-simulator
docker compose --profile load-test down -v
"""

[tasks."aws:load-test:smoke"]
description = "Run load tests against AWS deployment"
dir = "e2e"
depends = ["ui-test:install"]
run = """
BASE_URL=$(aws cloudformation describe-stacks \
--stack-name "StickerlandiaSharedResources-${ENV:-dev}" \
--query "Stacks[0].Outputs[?OutputKey=='BaseUrl'].OutputValue" \
--output text)
DEPLOYMENT_HOST_URL=$(aws cloudformation describe-stacks \
--stack-name "StickerlandiaSharedResources-${ENV:-dev}" \
--query "Stacks[0].Outputs[?OutputKey=='BaseUrl'].OutputValue" \
--output text)
echo "Running tests against: $BASE_URL"
BASE_URL=$BASE_URL DEPLOYMENT_HOST_URL=$DEPLOYMENT_HOST_URL npx playwright test
"""
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
// Copyright 2025 Datadog, Inc.

using System.Diagnostics;
using System.Text.Json.Nodes;
using Amazon.EventBridge;
using Amazon.EventBridge.Model;
using CloudNative.CloudEvents;
using CloudNative.CloudEvents.SystemTextJson;
using Datadog.Trace;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Saunter.Attributes;
Expand All @@ -29,7 +31,8 @@ namespace Stickerlandia.PrintService.AWS;
public class EventBridgeEventPublisher(
ILogger<EventBridgeEventPublisher> logger,
IAmazonEventBridge client,
IOptions<AwsConfiguration> awsConfiguration) : IPrintServiceEventPublisher
IOptions<AwsConfiguration> awsConfiguration,
IDatadogTransactionTracker transactionTracker) : IPrintServiceEventPublisher
{
[Channel("printJobs.queued.v1")]
[PublishOperation(typeof(PrintJobQueuedEvent))]
Expand All @@ -47,6 +50,7 @@ public async Task PublishPrintJobQueuedEvent(PrintJobQueuedEvent printJobQueuedE
};

await PublishCloudEventAsync(cloudEvent);
await transactionTracker.TrackTransactionAsync(printJobQueuedEvent.PrintJobId, "print-job-queued");
}

[Channel("printJobs.failed.v1")]
Expand Down Expand Up @@ -139,14 +143,26 @@ internal async Task PublishCloudEventAsync(CloudEvent cloudEvent)
var data = formatter.EncodeStructuredModeMessage(cloudEvent, out _);
var jsonString = System.Text.Encoding.UTF8.GetString(data.Span);

if (Tracer.Instance.ActiveScope is not null)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This adds DSM support to the AWS publishing

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We never call TrackTransactionAsync in this path, only in the kafka worker, which seems like it is needed

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{
var jsonNode = JsonNode.Parse(jsonString)!;
new SpanContextInjector().InjectIncludingDsm(jsonNode, SetHeader, Tracer.Instance.ActiveScope.Span.Context, "eventbridge", cloudEvent.Type!);
jsonString = jsonNode.ToJsonString();
}
else
{
Log.GenericWarning(logger, "DSM injection skipped for EventBridge: no active Datadog scope", null);
activity?.SetTag("dsm.injection_skipped", "no active scope");
}

var response = await client.PutEventsAsync(new PutEventsRequest()
{
Entries = new List<PutEventsRequestEntry>(1)
{
new()
{
EventBusName = awsConfiguration.Value.EventBusName,
Source = $"{Environment.GetEnvironmentVariable("ENV") ?? "dev"}.users",
Source = $"{Environment.GetEnvironmentVariable("ENV") ?? "dev"}.print",
DetailType = cloudEvent.Type,
Detail = jsonString,
}
Expand All @@ -171,4 +187,11 @@ internal async Task PublishCloudEventAsync(CloudEvent cloudEvent)
throw;
}
}

private static void SetHeader(JsonNode jsonNode, string key, string value)
{
if (jsonNode["_datadog"] == null) jsonNode["_datadog"] = new JsonObject();

jsonNode["_datadog"]![key] = value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Stickerlandia.PrintService.Core;
using Stickerlandia.PrintService.Core.Observability;
using Stickerlandia.PrintService.Core.Outbox;
using Stickerlandia.PrintService.Core.PrintJobs;

Expand Down Expand Up @@ -61,6 +62,9 @@ public static IServiceCollection AddAwsAdapters(this IServiceCollection services

services.AddSingleton<IPrintServiceEventPublisher, EventBridgeEventPublisher>();

services.AddHttpClient();
services.AddSingleton<IDatadogTransactionTracker, DatadogTransactionTracker>();

return services;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using CloudNative.CloudEvents;
using CloudNative.CloudEvents.SystemTextJson;
using Confluent.Kafka;
using Datadog.Trace;
using Microsoft.Extensions.Logging;
using Saunter.Attributes;
using Stickerlandia.PrintService.Core;
Expand All @@ -17,7 +18,7 @@

namespace Stickerlandia.PrintService.Agnostic;

public class KafkaEventPublisher(ProducerConfig config, ILogger<KafkaEventPublisher> logger) : IPrintServiceEventPublisher
public class KafkaEventPublisher(ProducerConfig config, ILogger<KafkaEventPublisher> logger, IDatadogTransactionTracker transactionTracker) : IPrintServiceEventPublisher
{
[Channel("printJobs.queued.v1")]
[PublishOperation(typeof(PrintJobQueuedEvent))]
Expand All @@ -34,7 +35,8 @@ public async Task PublishPrintJobQueuedEvent(PrintJobQueuedEvent printJobQueuedE
Data = printJobQueuedEvent
};

await Publish<PrinterRegisteredEvent>(cloudEvent);
await Publish<PrintJobQueuedEvent>(cloudEvent);
await transactionTracker.TrackTransactionAsync(printJobQueuedEvent.PrintJobId, "print-job-queued");
}

[Channel("printJobs.failed.v1")]
Expand All @@ -52,7 +54,7 @@ public async Task PublishPrintJobFailedEvent(PrintJobFailedEvent printJobFailedE
Data = printJobFailedEvent
};

await Publish<PrinterRegisteredEvent>(cloudEvent);
await Publish<PrintJobFailedEvent>(cloudEvent);
}

[Channel("print.printerRegistered.v1")]
Expand Down Expand Up @@ -126,13 +128,33 @@ private async Task Publish<T>(CloudEvent cloudEvent)
var formatter = new JsonEventFormatter<T>();
var data = formatter.EncodeStructuredModeMessage(cloudEvent, out _);

var message = new Message<string, string>
{
Key = cloudEvent.Id!,
Value = Encoding.UTF8.GetString(data.Span)
};

if (Tracer.Instance.ActiveScope is not null)
{
message.Headers = new Headers();
new SpanContextInjector().InjectIncludingDsm(
message.Headers,
(headers, key, value) => headers.Add(key, Encoding.UTF8.GetBytes(value)),
Tracer.Instance.ActiveScope.Span.Context,
"kafka",
cloudEvent.Type!);
}
else
{
Log.GenericWarning(logger, "DSM injection skipped for Kafka: no active Datadog scope", null);
activity?.SetTag("dsm.injection_skipped", "no active scope");
}

using var producer = new ProducerBuilder<string, string>(config).Build();

try
{
var deliveryReport = await producer.ProduceAsync(cloudEvent.Type,
new Message<string, string> { Key = cloudEvent.Id!, Value = Encoding.UTF8.GetString(data.Span) },
default);
var deliveryReport = await producer.ProduceAsync(cloudEvent.Type, message, default);

if (deliveryReport.Status == PersistenceStatus.PossiblyPersisted)
{
Expand Down
Loading
Loading