Skip to content

Feature/message queue abstraction - #20

Merged
dcl10 merged 5 commits into
mainfrom
feature/message-queue-abstraction
May 1, 2026
Merged

Feature/message queue abstraction#20
dcl10 merged 5 commits into
mainfrom
feature/message-queue-abstraction

Conversation

@dcl10

@dcl10 dcl10 commented May 1, 2026

Copy link
Copy Markdown
Contributor

Description

Adds the message queue infrastructure that will underpin the LLM-driven recommendation system (issue #8). This is the first of three PRs — it lays the foundation that the outbound dispatch (PR 2) and inbound team-building (PR 3) services will build on.

IMessageQueue<T> — a generic abstraction with two methods:

  • PublishAsync — serialise and send a message
  • ConsumeAsync — returns an IAsyncEnumerable<T> stream; the implementation polls the queue, yields each message, then deletes it (acknowledges) before moving to the next. Malformed messages are deleted without yielding so they don't block the stream.

AzureStorageQueueMessageQueue<T> — the concrete implementation backed by Azure Queue Storage. Messages are JSON-serialised with snake_case naming (matching the rest of the API) and base64-encoded by the SDK.

Data contracts — three record types that cross the boundary with the LLM service:

  • ProjectDescriptionPayload — sent outbound; contains only project description data (no user skill data ever leaves the backend)
  • SkillRequirementsResult — received inbound from the LLM service
  • RoleRequirement — a role name and the list of skills required to fill it

Config & DIMessageQueueOptions binds from MessageQueue in app settings (connection string + queue names). AddMessageQueues extension registers both typed IMessageQueue<T> singletons.

Linked issues

(Optional) Screenshots

N/A — backend infrastructure change with no UI impact.

dcl10 and others added 5 commits May 1, 2026 11:58
Defines the generic IMessageQueue<T> abstraction with PublishAsync and
ConsumeAsync (IAsyncEnumerable stream), plus the three payload types
(ProjectDescriptionPayload, SkillRequirementsResult, RoleRequirement)
that cross the boundary between the backend and the LLM service.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements IMessageQueue<T> with Azure Queue Storage: publishes via
SendMessageAsync and consumes via an IAsyncEnumerable polling loop
that deletes each message after it is yielded. Adds MessageQueueOptions
config and an AddMessageQueues extension registered in Program.cs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers: publish serialises to snake_case JSON, consume yields and
deletes messages, malformed messages are skipped but still deleted,
and consuming with a pre-cancelled token does not poll the queue.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cancel after all expected messages are received rather than after the
first, and use two valid messages in the malformed-skip test so the
count assertion proves both were yielded rather than just that we
stopped early.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
AddMessageQueues was instantiating QueueClient at registration time,
which threw when the connection string was absent in CI. Changed to
factory delegates so construction is deferred until first resolve.
Added IMessageQueue<T> mocks to ApiFactory so integration tests never
resolve the real implementation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dcl10
dcl10 merged commit 597de79 into main May 1, 2026
1 check passed
@dcl10
dcl10 deleted the feature/message-queue-abstraction branch May 1, 2026 11:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant