Skip to content

Hamza/feature/bus gateway - #188

Merged
hamzahalq merged 3 commits into
releases/r8.0from
hamza/feature/bus-gateway
Jul 5, 2026
Merged

Hamza/feature/bus gateway#188
hamzahalq merged 3 commits into
releases/r8.0from
hamza/feature/bus-gateway

Conversation

@hamzahalq

Copy link
Copy Markdown
Contributor

No description provided.

mmalkhatib and others added 2 commits July 2, 2026 15:36
Bus-triggered counterpart to the API gateway: when a message arrives for a
document, each matching route runs its subscription, optionally injecting a
partner's values.

- New SubscriptionType.BusGateway (32) + create/update validation
- BusGateway + BusGatewayRoute entities, EF config (base + PgSql), and
  migrations for PgSql/MySql/MsSql
- FilterResult.GatewayHits; FilterService evaluates routes and excludes gateway
  subs from normal matching; XchangeService dispatches gateway hits via the
  existing API-gateway xchange path (partner + globals injection)
- Cache routes per document; CRUD handlers under Resources/BusGateways
- Handle BusGateway in the Xchange created-event switch
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@hamzahalq, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 32 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository: simplify9/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: acfa4140-4ae7-41bc-91fc-600cdb6efb0e

📥 Commits

Reviewing files that changed from the base of the PR and between 331e556 and 39f635b.

📒 Files selected for processing (4)
  • SW.Bitween.Api/Resources/BusGateways/Create.cs
  • SW.Bitween.Api/Resources/BusGateways/Update.cs
  • SW.Bitween.Api/Resources/Subscriptions/Create.cs
  • SW.Bitween.Sdk/Model/BusGateway.cs
📝 Walkthrough

Walkthrough

This PR introduces a BusGateway feature: new domain entities (BusGateway, BusGatewayRoute) and a SubscriptionType.BusGateway enum value, EF Core mappings and migrations across MsSql/MySql/PgSql, SDK DTOs, CRUD/route API handlers, cache warm-up support, and FilterService/XchangeService integration for gateway-hit routing.

Changes

BusGateway feature

Layer / File(s) Summary
Domain entities and SubscriptionType extension
SW.Bitween.Api/Domain/Gateway/BusGateway.cs, .../BusGatewayRoute.cs, SW.Bitween.Sdk/Model/Subscription.cs, SW.Bitween.Api/Domain/Subscription/Subscription.cs, SW.Bitween.Api/Domain/Xchange/Xchange.cs
Adds BusGateway/BusGatewayRoute entities, SubscriptionType.BusGateway = 32, allows the type in Subscription's constructor validation, and maps it to InternalXchangeCreatedEvent in Xchange.
SDK DTOs and FilterResult contract
SW.Bitween.Sdk/Model/BusGateway.cs, SW.Bitween.Sdk/Model/FilterResult.cs
New BusGatewayCreate/Update/Row, route DTO/create/update/removal request classes, and FilterResult.GatewayHits/GatewayHit.
EF Core model mapping and cache interface
SW.Bitween.Api/Data/BitweenDbContext.cs, SW.Bitween.PgSql/BitweenDbContext.cs, SW.Bitween.Api/Interfaces/IInfolinkCache.cs
Configures BusGateway/BusGatewayRoute entities (keys, FKs, MatchExpression conversion) and adds ListBusGatewayRoutesByDocumentAsync to the cache interface.
Database migrations
SW.Bitween.MsSql/Migrations/...AddBusGateway*, SW.Bitween.MySql/Migrations/...AddBusGateway*, SW.Bitween.PgSql/Migrations/...AddBusGateway*, */Migrations/BitweenDbContextModelSnapshot.cs
Adds AddBusGateway migrations/designers creating gateway tables with FKs/indexes and updates model snapshots for all three providers.
BusGateway API resource handlers
SW.Bitween.Api/Resources/BusGateways/*.cs
Implements Create, Get, Update, Delete, Search, AddRoute, RemoveRoute, UpdateRoute handlers with access checks, existence validation, and cache revoke broadcasts.
Cache warm-up and lookup
SW.Bitween.Api/Services/Caching/InMemoryInfolinkCache.cs
Loads BusGateway with Routes into cache, adds document-scoped route lookup, and includes BusGateway in cache invalidation.
Filter/Xchange routing and match-spec fix
SW.Bitween.Api/Services/FilterService.cs, SW.Bitween.Api/Services/XchangeService.cs, SW.Bitween.Sdk/JsonConverters/PropertyMatchSpecificationJsonConverter.cs
Excludes BusGateway subscriptions from normal matching, evaluates gateway routes into GatewayHits, creates Xchanges from those hits with partner resolution, and fixes single-sided and/or evaluation.
Subscription validation updates
SW.Bitween.Api/Resources/Subscriptions/Create.cs, .../Update.cs
Treats BusGateway like GatewayApiCall for construction and PartnerId nullability, and validates match specs by Path.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • simplify9/Bitween-api#116: Modifies the same Subscription/Xchange constructor code paths this PR extends for BusGateway.
  • simplify9/Bitween-api#124: Touches the same SubscriptionType switch in Xchange.cs that this PR extends with a gateway case.
  • simplify9/Bitween-api#149: Adds Xchange.PartnerId and partner injection logic aligned with this PR's GatewayHits/partner resolution in XchangeService.

Suggested labels: database, risk:high

Suggested reviewers: AhmadRAbuhussein

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive No description was provided, so there is no meaningful text to assess against the changeset. Add a short description summarizing the new bus gateway entities, handlers, and migration work.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title references the bus gateway feature, which matches the main change, though it is branch-like and not very polished.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
SW.Bitween.Sdk/JsonConverters/PropertyMatchSpecificationJsonConverter.cs (1)

56-98: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate single-sided fallback logic between EvaluateAnd/EvaluateOr.

Both methods repeat the same three checks (both-present, left-only, right-only) verbatim; only the combinator differs. Extract a shared helper.

♻️ Proposed refactor
-    IPropertyMatchSpecification EvaluateAnd(JObject jObj)
-    {
-        var jLeft = jObj.Property("left")?.Value;
-        var jRight = jObj.Property("right")?.Value;
-        if (jLeft is JObject jLeftObj && jRight is JObject jRightObj)
-        {
-            return new AndSpec(Evaluate(jLeftObj), Evaluate(jRightObj));
-        }
-
-        if (jLeft is JObject soleLeftObj && IsNullOrMissing(jRight))
-        {
-            return Evaluate(soleLeftObj);
-        }
-
-        if (jRight is JObject soleRightObj && IsNullOrMissing(jLeft))
-        {
-            return Evaluate(soleRightObj);
-        }
-
-        throw new JsonSerializationException("Invalid Match Specification Format");
-    }
-
-    IPropertyMatchSpecification EvaluateOr(JObject jObj)
-    {
-        var jLeft = jObj.Property("left")?.Value;
-        var jRight = jObj.Property("right")?.Value;
-        if (jLeft is JObject jLeftObj && jRight is JObject jRightObj)
-        {
-            return new OrSpec(Evaluate(jLeftObj), Evaluate(jRightObj));
-        }
-
-        if (jLeft is JObject soleLeftObj && IsNullOrMissing(jRight))
-        {
-            return Evaluate(soleLeftObj);
-        }
-
-        if (jRight is JObject soleRightObj && IsNullOrMissing(jLeft))
-        {
-            return Evaluate(soleRightObj);
-        }
-
-        throw new JsonSerializationException("Invalid Match Specification Format");
-    }
+    IPropertyMatchSpecification EvaluateAnd(JObject jObj) =>
+        EvaluateBinary(jObj, (l, r) => new AndSpec(l, r));
+
+    IPropertyMatchSpecification EvaluateOr(JObject jObj) =>
+        EvaluateBinary(jObj, (l, r) => new OrSpec(l, r));
+
+    IPropertyMatchSpecification EvaluateBinary(JObject jObj,
+        Func<IPropertyMatchSpecification, IPropertyMatchSpecification, IPropertyMatchSpecification> combine)
+    {
+        var jLeft = jObj.Property("left")?.Value;
+        var jRight = jObj.Property("right")?.Value;
+        if (jLeft is JObject jLeftObj && jRight is JObject jRightObj)
+            return combine(Evaluate(jLeftObj), Evaluate(jRightObj));
+
+        if (jLeft is JObject soleLeftObj && IsNullOrMissing(jRight))
+            return Evaluate(soleLeftObj);
+
+        if (jRight is JObject soleRightObj && IsNullOrMissing(jLeft))
+            return Evaluate(soleRightObj);
+
+        throw new JsonSerializationException("Invalid Match Specification Format");
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SW.Bitween.Sdk/JsonConverters/PropertyMatchSpecificationJsonConverter.cs`
around lines 56 - 98, Both EvaluateAnd and EvaluateOr duplicate the same
left/right fallback checks, with only the spec combinator changing. Extract the
shared branching logic into a helper inside
PropertyMatchSpecificationJsonConverter that handles both-present, left-only,
and right-only cases, and pass in the constructor/combinator so EvaluateAnd and
EvaluateOr simply delegate to it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@SW.Bitween.Api/Resources/BusGateways/Create.cs`:
- Around line 11-42: Add validation for BusGatewayCreate.Name before
Create.Handle persists the entity, since it currently stores model.Name directly
without any FluentValidation guard. Update the BusGatewayCreate validator (or
add one if missing) to require a non-empty, non-whitespace Name, and ensure the
Create command path in Create.Handle only accepts validated input before saving
the BusGateway entity.

In `@SW.Bitween.Api/Resources/BusGateways/Update.cs`:
- Around line 33-38: The Update flow in BusGateway resource currently persists
entity.Name directly without validating model.Name, so empty or whitespace-only
names can be saved. Add input validation in the update handler before assigning
and saving: check model.Name is not null/empty/whitespace, reject invalid values
with the existing validation/error pattern, and only proceed with entity.Name,
SaveChangesAsync, and BroadcastRevoke when the name is valid.

In `@SW.Bitween.Api/Resources/Subscriptions/Create.cs`:
- Around line 39-42: In Create.cs, the GatewayApiCall and BusGateway path in the
create flow is silently dropping a supplied PartnerId because Subscription(name,
documentId, type) always sets it to null. Update the create validation and
entity construction to match Subscriptions/Update.cs: if model.Type is
GatewayApiCall or BusGateway and model.PartnerId has a value, reject the request
instead of ignoring it. Use the existing Create validator and the subscription
creation branch to ensure PartnerId is only accepted for types that support it.

In `@SW.Bitween.Api/Services/XchangeService.cs`:
- Around line 420-436: Use the cached global adapter values list instead of
querying the DB directly in XchangeService’s bus-gateway route handling. Replace
the _dbContext.Set<GlobalAdapterValuesSet>().ToArrayAsync() call with
_BitweenCache.ListGlobalAdapterValuesSetsAsync(), and keep the existing loop
over result.GatewayHits unchanged so the partner/global injection path still
works through the cache layer.

In `@SW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.cs`:
- Around line 38-89: The BusGatewayRoutes table currently allows duplicate route
rows for the same BusGatewayId, SubscriptionId, and PartnerId, so add a DB-level
uniqueness guard in the AddBusGateway migration. Update the BusGatewayRoutes
creation in AddBusGateway to define a unique index or alternate key over the
route identity columns, and ensure it aligns with the AddRoute/UpdateRoute
behavior so duplicate subscription+partner routes cannot be inserted.

In `@SW.Bitween.Sdk/Model/BusGateway.cs`:
- Around line 12-15: Remove the Routes property from BusGatewayUpdate so the
update contract only exposes Name and does not suggest route changes are
supported here. Update the BusGatewayUpdate model in BusGateway.cs to inherit
the create fields without Routes, and keep route modifications confined to the
dedicated route endpoints and their DTOs/handlers.

---

Outside diff comments:
In `@SW.Bitween.Sdk/JsonConverters/PropertyMatchSpecificationJsonConverter.cs`:
- Around line 56-98: Both EvaluateAnd and EvaluateOr duplicate the same
left/right fallback checks, with only the spec combinator changing. Extract the
shared branching logic into a helper inside
PropertyMatchSpecificationJsonConverter that handles both-present, left-only,
and right-only cases, and pass in the constructor/combinator so EvaluateAnd and
EvaluateOr simply delegate to it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: simplify9/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 14a81a00-96b5-499d-9ac9-b38e285040c6

📥 Commits

Reviewing files that changed from the base of the PR and between 7ec42ce and 331e556.

📒 Files selected for processing (33)
  • SW.Bitween.Api/Data/BitweenDbContext.cs
  • SW.Bitween.Api/Domain/Gateway/BusGateway.cs
  • SW.Bitween.Api/Domain/Gateway/BusGatewayRoute.cs
  • SW.Bitween.Api/Domain/Subscription/Subscription.cs
  • SW.Bitween.Api/Domain/Xchange/Xchange.cs
  • SW.Bitween.Api/Interfaces/IInfolinkCache.cs
  • SW.Bitween.Api/Resources/BusGateways/AddRoute.cs
  • SW.Bitween.Api/Resources/BusGateways/Create.cs
  • SW.Bitween.Api/Resources/BusGateways/Delete.cs
  • SW.Bitween.Api/Resources/BusGateways/Get.cs
  • SW.Bitween.Api/Resources/BusGateways/RemoveRoute.cs
  • SW.Bitween.Api/Resources/BusGateways/Search.cs
  • SW.Bitween.Api/Resources/BusGateways/Update.cs
  • SW.Bitween.Api/Resources/BusGateways/UpdateRoute.cs
  • SW.Bitween.Api/Resources/Subscriptions/Create.cs
  • SW.Bitween.Api/Resources/Subscriptions/Update.cs
  • SW.Bitween.Api/Services/Caching/InMemoryInfolinkCache.cs
  • SW.Bitween.Api/Services/FilterService.cs
  • SW.Bitween.Api/Services/XchangeService.cs
  • SW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.Designer.cs
  • SW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.cs
  • SW.Bitween.MsSql/Migrations/BitweenDbContextModelSnapshot.cs
  • SW.Bitween.MySql/Migrations/20260702125335_AddBusGateway.Designer.cs
  • SW.Bitween.MySql/Migrations/20260702125335_AddBusGateway.cs
  • SW.Bitween.MySql/Migrations/BitweenDbContextModelSnapshot.cs
  • SW.Bitween.PgSql/BitweenDbContext.cs
  • SW.Bitween.PgSql/Migrations/20260702125227_AddBusGateway.Designer.cs
  • SW.Bitween.PgSql/Migrations/20260702125227_AddBusGateway.cs
  • SW.Bitween.PgSql/Migrations/BitweenDbContextModelSnapshot.cs
  • SW.Bitween.Sdk/JsonConverters/PropertyMatchSpecificationJsonConverter.cs
  • SW.Bitween.Sdk/Model/BusGateway.cs
  • SW.Bitween.Sdk/Model/FilterResult.cs
  • SW.Bitween.Sdk/Model/Subscription.cs
📜 Review details
🧰 Additional context used
🪛 Betterleaks (1.6.0)
SW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.Designer.cs

[high] 1079-1079: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

SW.Bitween.PgSql/Migrations/20260702125227_AddBusGateway.Designer.cs

[high] 1297-1297: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

SW.Bitween.MySql/Migrations/20260702125335_AddBusGateway.Designer.cs

[high] 1076-1076: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (34)
SW.Bitween.Api/Domain/Gateway/BusGateway.cs (1)

1-16: LGTM!

SW.Bitween.Api/Domain/Gateway/BusGatewayRoute.cs (1)

1-25: LGTM!

SW.Bitween.Sdk/Model/Subscription.cs (1)

15-15: LGTM!

SW.Bitween.Api/Domain/Subscription/Subscription.cs (1)

38-44: LGTM!

SW.Bitween.Api/Domain/Xchange/Xchange.cs (1)

33-34: LGTM!

SW.Bitween.Sdk/Model/FilterResult.cs (1)

9-27: LGTM!

SW.Bitween.PgSql/Migrations/BitweenDbContextModelSnapshot.cs (1)

409-414: Same MatchExpression converter concern as above.

SW.Bitween.Api/Data/BitweenDbContext.cs (1)

118-146: LGTM!

SW.Bitween.PgSql/BitweenDbContext.cs (1)

143-171: LGTM!

SW.Bitween.Api/Interfaces/IInfolinkCache.cs (1)

3-10: LGTM!

SW.Bitween.PgSql/Migrations/20260702125227_AddBusGateway.Designer.cs (1)

409-414: 🗄️ Data Integrity & Integration

Verify the generated model preserves the MatchExpression converter.

SW.Bitween.PgSql/BitweenDbContext.cs maps BusGatewayRoute.MatchExpression through MatchSpecValueConverter, and SW.Bitween.Api/Services/FilterService.cs later calls IsMatch(...) on the deserialized object. This generated model records the property as plain string; please confirm that is intentional. Otherwise future migrations will drift from the runtime model and route matching will stop round-tripping.

SW.Bitween.PgSql/Migrations/20260702125227_AddBusGateway.cs (1)

15-105: LGTM!

SW.Bitween.MySql/Migrations/20260702125335_AddBusGateway.Designer.cs (2)

285-318: 🗄️ Data Integrity & Integration

Duplicate of MsSql Designer.cs comment on BusGateway/Document cardinality.

Same missing unique constraint on DocumentId as flagged in SW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.Designer.cs (Lines 287-320); root cause lives in the shared domain model, not per-provider migration code.


1-284: LGTM!

Also applies to: 320-1226

SW.Bitween.MySql/Migrations/BitweenDbContextModelSnapshot.cs (2)

20-20: 📐 Maintainability & Code Quality

Same ProductVersion regression as the MsSql snapshot (8.0.26 → 8.0.23).

See the equivalent comment on SW.Bitween.MsSql/Migrations/BitweenDbContextModelSnapshot.cs (Line 20) — confirm intended EF Core tooling version once and apply consistently across providers.


282-359: LGTM!

Also applies to: 999-1033, 1210-1214

SW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.Designer.cs (2)

287-320: 🗄️ Data Integrity & Integration

Verify BusGateway↔Document cardinality intent.

BusGateway has no unique index on DocumentId (contrast with ApiGateway.UrlName, which is unique at Line 249-250). If multiple BusGateway rows can reference the same Document, downstream routing (FilterService gateway-hit evaluation) may become ambiguous about which gateway's routes apply for a given document. Confirm this is intentional; if not, add a unique index on DocumentId.


322-363: LGTM!

Also applies to: 1014-1038, 1216-1219

SW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.cs (1)

1-37: LGTM!

Also applies to: 90-107

SW.Bitween.MsSql/Migrations/BitweenDbContextModelSnapshot.cs (2)

284-361: LGTM!

Also applies to: 999-1033, 1213-1217


20-20: 📐 Maintainability & Code Quality

ProductVersion 8.0.23 matches the repo’s EF Core version; no action needed.

			> Likely an incorrect or invalid review comment.
SW.Bitween.MySql/Migrations/20260702125335_AddBusGateway.cs (1)

1-117: LGTM!

SW.Bitween.Api/Resources/BusGateways/AddRoute.cs (1)

1-78: LGTM!

SW.Bitween.Api/Resources/BusGateways/Delete.cs (1)

1-43: LGTM!

SW.Bitween.Api/Resources/Subscriptions/Update.cs (1)

104-116: LGTM!

Also applies to: 255-266

SW.Bitween.Api/Resources/BusGateways/Get.cs (1)

11-20: 🔒 Security & Privacy

Clarify whether BusGateways/Get should be role-restricted. It returns gateway, route, subscription, and partner details with no access check; add the same guard used by the mutating handlers if this data should not be broadly readable.

SW.Bitween.Api/Resources/BusGateways/RemoveRoute.cs (1)

1-40: LGTM!

SW.Bitween.Api/Resources/BusGateways/UpdateRoute.cs (1)

1-53: LGTM!

SW.Bitween.Api/Services/Caching/InMemoryInfolinkCache.cs (1)

9-9: LGTM!

Also applies to: 44-52, 66-79, 192-192

SW.Bitween.Api/Services/FilterService.cs (2)

48-52: LGTM!


62-76: 🩺 Stability & Availability

GatewayHits is initialized in SW.Bitween.Sdk/Model/FilterResult.cs, so this null-reference concern doesn’t apply.

			> Likely an incorrect or invalid review comment.
SW.Bitween.Api/Services/XchangeService.cs (1)

402-419: LGTM!

SW.Bitween.Api/Resources/BusGateways/Search.cs (2)

25-34: 🎯 Functional Correctness

DocumentId is already inherited on BusGatewayRow, so this projection is valid.

			> Likely an incorrect or invalid review comment.

12-21: 🔒 Security & Privacy

Check BusGateways search access control. Search.cs has no local RequestContext/EnsureAccess gate; if read access isn’t enforced in the controller/dispatch layer, this should mirror the other BusGateway handlers and require AccountRole.Admin or AccountRole.Member.

Comment thread SW.Bitween.Api/Resources/BusGateways/Create.cs
Comment thread SW.Bitween.Api/Resources/BusGateways/Update.cs
Comment thread SW.Bitween.Api/Resources/Subscriptions/Create.cs
Comment on lines +420 to +436
// Bus-gateway routes: run the assigned subscription with the route's optional partner values,
// reusing the same xchange path the API gateway uses (partner + globals injection).
var globalAdapterValuesSets = await _dbContext.Set<GlobalAdapterValuesSet>().ToArrayAsync();
foreach (var hit in result.GatewayHits)
{
var subscription = await _BitweenCache.SubscriptionByIdAsync(hit.SubscriptionId);
if (subscription == null)
{
_logger.LogWarning(
"Bus gateway route references subscription {SubscriptionId}, which is not active; skipping.",
hit.SubscriptionId);
continue;
}

var partner = hit.PartnerId.HasValue
? await _dbContext.FindAsync<Partner>(hit.PartnerId.Value)
: null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Use cached ListGlobalAdapterValuesSetsAsync instead of a direct DB query.

_BitweenCache.ListGlobalAdapterValuesSetsAsync() already exists and is cached (see InMemoryInfolinkCache.cs). Querying _dbContext.Set<GlobalAdapterValuesSet>() directly here re-hits the DB on every gateway-hit message and bypasses the existing cache layer this class already depends on for subscriptions.

Proposed fix
-        var globalAdapterValuesSets = await _dbContext.Set<GlobalAdapterValuesSet>().ToArrayAsync();
+        var globalAdapterValuesSets = await _BitweenCache.ListGlobalAdapterValuesSetsAsync();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Bus-gateway routes: run the assigned subscription with the route's optional partner values,
// reusing the same xchange path the API gateway uses (partner + globals injection).
var globalAdapterValuesSets = await _dbContext.Set<GlobalAdapterValuesSet>().ToArrayAsync();
foreach (var hit in result.GatewayHits)
{
var subscription = await _BitweenCache.SubscriptionByIdAsync(hit.SubscriptionId);
if (subscription == null)
{
_logger.LogWarning(
"Bus gateway route references subscription {SubscriptionId}, which is not active; skipping.",
hit.SubscriptionId);
continue;
}
var partner = hit.PartnerId.HasValue
? await _dbContext.FindAsync<Partner>(hit.PartnerId.Value)
: null;
// Bus-gateway routes: run the assigned subscription with the route's optional partner values,
// reusing the same xchange path the API gateway uses (partner + globals injection).
var globalAdapterValuesSets = await _BitweenCache.ListGlobalAdapterValuesSetsAsync();
foreach (var hit in result.GatewayHits)
{
var subscription = await _BitweenCache.SubscriptionByIdAsync(hit.SubscriptionId);
if (subscription == null)
{
_logger.LogWarning(
"Bus gateway route references subscription {SubscriptionId}, which is not active; skipping.",
hit.SubscriptionId);
continue;
}
var partner = hit.PartnerId.HasValue
? await _dbContext.FindAsync<Partner>(hit.PartnerId.Value)
: null;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SW.Bitween.Api/Services/XchangeService.cs` around lines 420 - 436, Use the
cached global adapter values list instead of querying the DB directly in
XchangeService’s bus-gateway route handling. Replace the
_dbContext.Set<GlobalAdapterValuesSet>().ToArrayAsync() call with
_BitweenCache.ListGlobalAdapterValuesSetsAsync(), and keep the existing loop
over result.GatewayHits unchanged so the partner/global injection path still
works through the cache layer.

Comment on lines +38 to +89
migrationBuilder.CreateTable(
name: "BusGatewayRoutes",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
BusGatewayId = table.Column<int>(type: "int", nullable: false),
SubscriptionId = table.Column<int>(type: "int", nullable: false),
PartnerId = table.Column<int>(type: "int", nullable: true),
MatchExpression = table.Column<string>(type: "nvarchar(max)", nullable: true),
CreatedOn = table.Column<DateTime>(type: "datetime2", nullable: false),
CreatedBy = table.Column<string>(type: "nvarchar(max)", nullable: true),
ModifiedOn = table.Column<DateTime>(type: "datetime2", nullable: true),
ModifiedBy = table.Column<string>(type: "nvarchar(max)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_BusGatewayRoutes", x => x.Id);
table.ForeignKey(
name: "FK_BusGatewayRoutes_BusGateways_BusGatewayId",
column: x => x.BusGatewayId,
principalTable: "BusGateways",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_BusGatewayRoutes_Partners_PartnerId",
column: x => x.PartnerId,
principalTable: "Partners",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_BusGatewayRoutes_Subscriptions_SubscriptionId",
column: x => x.SubscriptionId,
principalTable: "Subscriptions",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});

migrationBuilder.CreateIndex(
name: "IX_BusGatewayRoutes_BusGatewayId",
table: "BusGatewayRoutes",
column: "BusGatewayId");

migrationBuilder.CreateIndex(
name: "IX_BusGatewayRoutes_PartnerId",
table: "BusGatewayRoutes",
column: "PartnerId");

migrationBuilder.CreateIndex(
name: "IX_BusGatewayRoutes_SubscriptionId",
table: "BusGatewayRoutes",
column: "SubscriptionId");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Consider a uniqueness guard for route definitions.

No DB-level constraint prevents duplicate (BusGatewayId, SubscriptionId, PartnerId) route rows. If the API layer (AddRoute/UpdateRoute) doesn't already dedupe, this table could accumulate conflicting/duplicate routes for the same subscription+partner pair.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@SW.Bitween.MsSql/Migrations/20260702125359_AddBusGateway.cs` around lines 38
- 89, The BusGatewayRoutes table currently allows duplicate route rows for the
same BusGatewayId, SubscriptionId, and PartnerId, so add a DB-level uniqueness
guard in the AddBusGateway migration. Update the BusGatewayRoutes creation in
AddBusGateway to define a unique index or alternate key over the route identity
columns, and ensure it aligns with the AddRoute/UpdateRoute behavior so
duplicate subscription+partner routes cannot be inserted.

Comment thread SW.Bitween.Sdk/Model/BusGateway.cs
- Validate Name (required, max 200) on BusGateway create and update; reject
  empty/whitespace names
- Reject a supplied PartnerId for GatewayApiCall/BusGateway subscriptions on
  create instead of silently discarding it (mirrors Update)
- Drop the ignored Routes property from BusGatewayUpdate; it now lives on
  BusGatewayRow. Route changes go through the dedicated route endpoints
@hamzahalq
hamzahalq merged commit 204552e into releases/r8.0 Jul 5, 2026
2 checks passed
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.

2 participants