Agent skill
arch-cross-service-integration
Use when designing or implementing cross-service communication, data synchronization, or service boundary patterns.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/cross-service-integration
SKILL.md
Cross-Service Integration Workflow
When to Use This Skill
- Designing service-to-service communication
- Implementing data synchronization
- Analyzing service boundaries
- Troubleshooting cross-service issues
Pre-Flight Checklist
- Identify source and target services
- Determine data ownership
- Choose communication pattern (sync vs async)
- Map data transformation requirements
Service Boundaries
EasyPlatform Services
┌─────────────────────────────────────────────────────────────────────┐
│ EasyPlatform Platform │
├───────────────┬───────────────┬───────────────┬────────────────────┤
│ TextSnippet │ TextSnippet │ TextSnippet │ TextSnippet │
│ (Example) │ (Example) │ (Example) │ (Example) │
├───────────────┴───────────────┴───────────────┴────────────────────┤
│ Accounts Service │
│ (Authentication & Users) │
├─────────────────────────────────────────────────────────────────────┤
│ Shared Infrastructure │
│ RabbitMQ │ Redis │ MongoDB │ PostgreSQL │
└─────────────────────────────────────────────────────────────────────┘
Communication Patterns
Pattern 1: Entity Event Bus (Recommended)
Use when: Source service owns data, target services need copies.
Source Service Target Service
┌────────────┐ ┌────────────┐
│ Employee │──── Create ────▶ │ Repository │
│ Repository │ └────────────┘
└────────────┘ │
│ │
│ Auto-raise │
▼ ▼
┌────────────┐ ┌────────────┐
│ Producer │── RabbitMQ ────▶ │ Consumer │
└────────────┘ └────────────┘
Implementation:
// Producer (Source: Accounts)
internal sealed class EmployeeEntityEventBusMessageProducer
: PlatformCqrsEntityEventBusMessageProducer<EmployeeEntityEventBusMessage, Employee, string>
{
public override async Task<bool> HandleWhen(PlatformCqrsEntityEvent<Employee> @event)
=> @event.EntityData.IsActive || @event.CrudAction == PlatformCqrsEntityEventCrudAction.Deleted;
}
// Consumer (Target: TextSnippet)
internal sealed class UpsertEmployeeConsumer
: PlatformApplicationMessageBusConsumer<EmployeeEntityEventBusMessage>
{
public override async Task HandleLogicAsync(EmployeeEntityEventBusMessage message, string routingKey)
{
// Wait for dependencies
// Handle Create/Update/Delete
}
}
Pattern 2: Direct API Call
Use when: Real-time data needed, no local copy required.
// In TextSnippet, calling Accounts API
public class AccountsApiClient
{
private readonly HttpClient _client;
public async Task<UserDto?> GetUserAsync(string userId)
{
var response = await _client.GetAsync($"/api/User/{userId}");
if (!response.IsSuccessStatusCode) return null;
return await response.Content.ReadFromJsonAsync<UserDto>();
}
}
Considerations:
- Add circuit breaker for resilience
- Cache responses when possible
- Handle service unavailability
Pattern 3: Shared Database View (Anti-Pattern!)
:x: DO NOT USE: Violates service boundaries
// WRONG - Direct cross-service database access
var accountsData = await accountsDbContext.Users.ToListAsync();
Data Ownership Matrix
| Entity | Owner Service | Consumers |
|---|---|---|
| User | Accounts | All services |
| Employee | TextSnippet | TextSnippet, TextSnippet |
| Candidate | TextSnippet | TextSnippet (on hire) |
| Company | Accounts | All services |
| Survey | TextSnippet | TextSnippet |
Synchronization Patterns
Full Sync (Initial/Recovery)
// For initial data population or recovery
public class FullSyncJob : PlatformApplicationBackgroundJobExecutor
{
public override async Task ProcessAsync(object? param)
{
// Fetch all from source
var allEmployees = await sourceApi.GetAllAsync();
// Upsert to local
foreach (var batch in allEmployees.Batch(100))
{
await localRepo.CreateOrUpdateManyAsync(
batch.Select(MapToLocal),
dismissSendEvent: true);
}
}
}
Incremental Sync (Event-Driven)
// Normal operation via message bus
internal sealed class EmployeeSyncConsumer : PlatformApplicationMessageBusConsumer<EmployeeEventBusMessage>
{
public override async Task HandleLogicAsync(EmployeeEventBusMessage message, string routingKey)
{
// Check if newer than current (race condition prevention)
if (existing?.LastMessageSyncDate > message.CreatedUtcDate)
return;
// Apply change
await ApplyChange(message);
}
}
Conflict Resolution
// Use LastMessageSyncDate for ordering
entity.With(e => e.LastMessageSyncDate = message.CreatedUtcDate);
// Only update if message is newer
if (existing.LastMessageSyncDate <= message.CreatedUtcDate)
{
await repository.UpdateAsync(updatedEntity);
}
Integration Checklist
Before Integration
- Define data ownership clearly
- Document which fields sync
- Plan for missing dependencies
- Define conflict resolution strategy
Implementation
- Message defined in PlatformExampleApp.Shared
- Producer filters appropriate events
- Consumer waits for dependencies
- Race condition handling implemented
- Soft delete handled
Testing
- Create event flows correctly
- Update event flows correctly
- Delete event flows correctly
- Out-of-order messages handled
- Missing dependency handled
- Force sync works
Troubleshooting
Message Not Arriving
# Check RabbitMQ queues
rabbitmqctl list_queues
# Check producer is publishing
grep -r "HandleWhen" --include="*Producer.cs" -A 5
# Check consumer is registered
grep -r "AddConsumer" --include="*.cs"
Data Mismatch
# Compare source and target counts
# In source service DB
SELECT COUNT(*) FROM Employees WHERE IsActive = 1;
# In target service DB
SELECT COUNT(*) FROM SyncedEmployees;
Stuck Messages
// Check for waiting dependencies
Logger.LogWarning("Waiting for Company {CompanyId}", companyId);
// Force reprocess
await messageBus.PublishAsync(message.With(m => m.IsForceSync = true));
Anti-Patterns to AVOID
:x: Direct database access
// WRONG
await otherServiceDbContext.Table.ToListAsync();
:x: Synchronous cross-service calls in transaction
// WRONG
using var transaction = await db.BeginTransactionAsync();
await externalService.NotifyAsync(); // If fails, transaction stuck
await transaction.CommitAsync();
:x: No dependency waiting
// WRONG - FK violation if company not synced
await repo.CreateAsync(employee); // Employee.CompanyId references Company
// CORRECT
await Util.TaskRunner.TryWaitUntilAsync(() => companyRepo.AnyAsync(...));
:x: Ignoring message order
// WRONG - older message overwrites newer
await repo.UpdateAsync(entity);
// CORRECT - check timestamp
if (existing.LastMessageSyncDate <= message.CreatedUtcDate)
Verification Checklist
- Data ownership clearly defined
- Message bus pattern used (not direct DB)
- Dependencies waited for in consumers
- Race conditions handled with timestamps
- Soft delete synchronized properly
- Force sync mechanism available
- Monitoring/alerting in place
IMPORTANT Task Planning Notes
- Always plan and break many small todo tasks
- Always add a final review todo task to review the works done at the end to find any fix or enhancement needed
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?