Skip to content

Commit 7aa7aa9

Browse files
pm7yclaude
andcommitted
fix!: Send Service Bus events as single objects instead of arrays
Service Bus delivery now always serializes events as single JSON objects without array wrapping, matching Azure Event Grid's actual behavior. Previously events were wrapped in a single-element array which forced consumers to add unnecessary array-handling logic. Removes the singleEventDelivery configuration option in favour of always using the correct Azure behavior. Also updates the commit-msg hook to support the ! breaking change indicator per the Conventional Commits spec. BREAKING CHANGE: Service Bus message bodies are now single JSON objects instead of single-element arrays. Consumers that parse the array format will need to be updated. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 4fa9d50 commit 7aa7aa9

4 files changed

Lines changed: 18 additions & 60 deletions

File tree

.githooks/commit-msg

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,19 @@ if echo "$commit_msg" | grep -qE "^Merge "; then
1515
exit 0
1616
fi
1717

18-
# Conventional commit pattern: type(optional scope): description
18+
# Conventional commit pattern: type(optional scope)(optional !): description
1919
# Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert, deps
20-
pattern="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert|deps)(\(.+\))?: .+"
20+
# The optional ! before the colon indicates a breaking change.
21+
pattern="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert|deps)(\(.+\))?!?: .+"
2122

2223
if ! echo "$commit_msg" | head -1 | grep -qE "$pattern"; then
2324
echo ""
2425
echo "ERROR: Commit message does not follow Conventional Commits format."
2526
echo ""
2627
echo "Expected format: <type>: <description>"
2728
echo " <type>(<scope>): <description>"
29+
echo " <type>!: <description>"
30+
echo " <type>(<scope>)!: <description>"
2831
echo ""
2932
echo "Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert, deps"
3033
echo ""
@@ -33,8 +36,11 @@ if ! echo "$commit_msg" | head -1 | grep -qE "$pattern"; then
3336
echo " fix: resolve validation error"
3437
echo " docs: update README"
3538
echo " chore(deps): update dependencies"
39+
echo " fix!: change Service Bus message format"
40+
echo " feat(api)!: remove deprecated endpoint"
3641
echo ""
3742
echo "Note: There must be a space after the colon."
43+
echo " Use ! before the colon to indicate a breaking change."
3844
echo ""
3945
echo "Your commit message was:"
4046
echo " $(head -1 "$commit_msg_file")"

src/AzureEventGridSimulator.Tests/UnitTests/Subscribers/Delivery/ServiceBusEventDeliveryServiceTests.cs

Lines changed: 6 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ EventSchema schema
184184
}
185185

186186
[Fact]
187-
public void GivenEventGridFormatter_WhenSerializing_ThenReturnsJson()
187+
public void GivenEventGridFormatter_WhenSerializing_ThenReturnsJsonArray()
188188
{
189189
var formatter = _formatterFactory.GetFormatter(EventSchema.EventGridSchema);
190190
var evt = CreateTestEvent();
@@ -193,10 +193,12 @@ public void GivenEventGridFormatter_WhenSerializing_ThenReturnsJson()
193193

194194
json.ShouldNotBeNullOrEmpty();
195195
json.ShouldContain("test-event-id");
196+
json.TrimStart().ShouldStartWith("[");
197+
json.TrimEnd().ShouldEndWith("]");
196198
}
197199

198200
[Fact]
199-
public void GivenCloudEventFormatter_WhenSerializing_ThenReturnsJson()
201+
public void GivenCloudEventFormatter_WhenSerializing_ThenReturnsJsonArray()
200202
{
201203
var formatter = _formatterFactory.GetFormatter(EventSchema.CloudEventV1_0);
202204
var evt = CreateTestEvent();
@@ -205,6 +207,8 @@ public void GivenCloudEventFormatter_WhenSerializing_ThenReturnsJson()
205207

206208
json.ShouldNotBeNullOrEmpty();
207209
json.ShouldContain("test-event-id");
210+
json.TrimStart().ShouldStartWith("[");
211+
json.TrimEnd().ShouldEndWith("]");
208212
}
209213

210214
[Fact]
@@ -278,42 +282,4 @@ public void GivenEventGridFormatter_WhenSerializingSingle_ThenReturnsJsonWithout
278282
json.TrimStart().ShouldStartWith("{");
279283
json.TrimEnd().ShouldEndWith("}");
280284
}
281-
282-
[Fact]
283-
public void GivenSubscriptionWithSingleEventDelivery_WhenConfigured_ThenPropertyIsSet()
284-
{
285-
var subscription = new ServiceBusSubscriberSettings
286-
{
287-
Name = "TestSubscriber",
288-
ConnectionString =
289-
"Endpoint=sb://my-namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=abc123",
290-
Queue = "my-queue",
291-
SingleEventDelivery = true,
292-
};
293-
294-
subscription.SingleEventDelivery.ShouldBe(true);
295-
}
296-
297-
[Fact]
298-
public void GivenSubscriptionWithoutSingleEventDelivery_WhenConfigured_ThenPropertyIsNull()
299-
{
300-
var subscription = CreateValidQueueSettings();
301-
302-
subscription.SingleEventDelivery.ShouldBeNull();
303-
}
304-
305-
[Fact]
306-
public void GivenSubscriptionWithSingleEventDeliveryFalse_WhenConfigured_ThenPropertyIsFalse()
307-
{
308-
var subscription = new ServiceBusSubscriberSettings
309-
{
310-
Name = "TestSubscriber",
311-
ConnectionString =
312-
"Endpoint=sb://my-namespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=abc123",
313-
Queue = "my-queue",
314-
SingleEventDelivery = false,
315-
};
316-
317-
subscription.SingleEventDelivery.ShouldBe(false);
318-
}
319285
}

src/AzureEventGridSimulator/Domain/Services/Delivery/ServiceBusEventDeliveryService.cs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,8 @@ CancellationToken cancellationToken
5858
subscription.DeliverySchema ?? delivery.Topic.OutputSchema ?? delivery.InputSchema;
5959
var formatter = formatterFactory.GetFormatter(deliverySchema);
6060

61-
// Serialize the event (use single event format if configured)
62-
var json =
63-
subscription.SingleEventDelivery == true
64-
? formatter.SerializeSingle(delivery.Event)
65-
: formatter.Serialize(delivery.Event);
61+
// Serialize as a single event (matches Azure Event Grid to Service Bus behavior)
62+
var json = formatter.SerializeSingle(delivery.Event);
6663

6764
// Get or create the sender
6865
var sender = GetOrCreateSender(subscription);
@@ -174,11 +171,8 @@ EventSchema inputSchema
174171
var deliverySchema = subscription.DeliverySchema ?? topic.OutputSchema ?? inputSchema;
175172
var formatter = formatterFactory.GetFormatter(deliverySchema);
176173

177-
// Serialize the event (use single event format if configured)
178-
var json =
179-
subscription.SingleEventDelivery == true
180-
? formatter.SerializeSingle(evt)
181-
: formatter.Serialize(evt);
174+
// Serialize as a single event (matches Azure Event Grid to Service Bus behavior)
175+
var json = formatter.SerializeSingle(evt);
182176

183177
// Get or create the sender
184178
var sender = GetOrCreateSender(subscription);

src/AzureEventGridSimulator/Infrastructure/Settings/Subscribers/ServiceBusSubscriberSettings.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,6 @@ public string? EffectiveConnectionString
130130
[JsonConverter(typeof(JsonStringEnumConverter))]
131131
public EventSchema? DeliverySchema { get; init; }
132132

133-
/// <summary>
134-
/// Gets or sets whether to send events as single objects without array wrapper.
135-
/// When true, events are sent as individual objects (Azure behavior for Service Bus).
136-
/// When false or null, events are sent in an array with a single event (default for backward compatibility).
137-
/// </summary>
138-
[JsonPropertyName("singleEventDelivery")]
139-
public bool? SingleEventDelivery { get; init; }
140-
141133
/// <summary>
142134
/// Gets or sets the retry policy for this subscriber.
143135
/// If null, default Azure Event Grid retry behavior is used (enabled with 30 attempts, 24h TTL).

0 commit comments

Comments
 (0)