Skip to content

Commit b48f2d3

Browse files
wow-mileyclaude
andcommitted
Refactor orchestrator dependencies with EnvironmentOrchestrator (#5)
Remove direct MeetingOrchestrator dependency from TicketOrchestrator to enable bidirectional communication between orchestrators. - Add MeetingSchedulingService functional interface for decoupling - Create EnvironmentOrchestrator to manage Meeting/Ticket/Event orchestrators - Update TicketOrchestrator to use MeetingSchedulingService - Update tests to use new architecture This allows orchestrators to call each other through the parent EnvironmentOrchestrator without circular dependencies. Co-authored-by: Claude <noreply@anthropic.com>
1 parent dd5c767 commit b48f2d3

7 files changed

Lines changed: 148 additions & 8 deletions

File tree

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package link.socket.kore.agents.events
2+
3+
import link.socket.kore.agents.events.api.AgentEventApi
4+
import link.socket.kore.agents.events.bus.EventBus
5+
import link.socket.kore.agents.events.meetings.Meeting
6+
import link.socket.kore.agents.events.meetings.MeetingOrchestrator
7+
import link.socket.kore.agents.events.meetings.MeetingRepository
8+
import link.socket.kore.agents.events.meetings.MeetingSchedulingService
9+
import link.socket.kore.agents.events.messages.AgentMessageApi
10+
import link.socket.kore.agents.events.tickets.TicketOrchestrator
11+
import link.socket.kore.agents.events.tickets.TicketRepository
12+
import link.socket.kore.agents.events.utils.ConsoleEventLogger
13+
import link.socket.kore.agents.events.utils.EventLogger
14+
15+
/**
16+
* Top-level orchestrator that coordinates all domain orchestrators.
17+
*
18+
* This class manages the lifecycle and dependencies of:
19+
* - MeetingOrchestrator: Handles meeting scheduling and lifecycle
20+
* - TicketOrchestrator: Handles ticket creation and workflow
21+
* - EventRouter: Routes events between subscribed agents
22+
*
23+
* By centralizing orchestrator management here, we avoid circular dependencies
24+
* between orchestrators while allowing them to communicate with each other
25+
* through this parent. For example, TicketOrchestrator can schedule meetings
26+
* without depending directly on MeetingOrchestrator.
27+
*/
28+
class EnvironmentOrchestrator(
29+
private val meetingRepository: MeetingRepository,
30+
private val ticketRepository: TicketRepository,
31+
private val eventBus: EventBus,
32+
private val messageApi: AgentMessageApi,
33+
private val eventApi: AgentEventApi,
34+
private val logger: EventLogger = ConsoleEventLogger(),
35+
) {
36+
/**
37+
* The meeting orchestrator that handles meeting lifecycle operations.
38+
*/
39+
val meetingOrchestrator: MeetingOrchestrator = MeetingOrchestrator(
40+
repository = meetingRepository,
41+
eventBus = eventBus,
42+
messageApi = messageApi,
43+
logger = logger,
44+
)
45+
46+
/**
47+
* The ticket orchestrator that handles ticket lifecycle operations.
48+
*
49+
* Uses a MeetingSchedulingService that delegates to the meetingOrchestrator,
50+
* allowing TicketOrchestrator to schedule meetings without direct dependency.
51+
*/
52+
val ticketOrchestrator: TicketOrchestrator = TicketOrchestrator(
53+
ticketRepository = ticketRepository,
54+
eventBus = eventBus,
55+
messageApi = messageApi,
56+
meetingSchedulingService = createMeetingSchedulingService(),
57+
logger = logger,
58+
)
59+
60+
/**
61+
* The event router that routes events to subscribed agents.
62+
*/
63+
val eventRouter: EventRouter = EventRouter(
64+
eventApi = eventApi,
65+
eventBus = eventBus,
66+
)
67+
68+
/**
69+
* Start all orchestrator services.
70+
*
71+
* This starts the event routing system. Individual orchestrators don't need
72+
* explicit startup as they respond to method calls.
73+
*/
74+
fun start() {
75+
eventRouter.startRouting()
76+
}
77+
78+
/**
79+
* Creates a MeetingSchedulingService that delegates to the meetingOrchestrator.
80+
*
81+
* This enables TicketOrchestrator to schedule meetings without directly
82+
* depending on MeetingOrchestrator, allowing for potential bidirectional
83+
* communication in the future where MeetingOrchestrator could also
84+
* interact with TicketOrchestrator.
85+
*/
86+
private fun createMeetingSchedulingService(): MeetingSchedulingService {
87+
return MeetingSchedulingService { meeting: Meeting, scheduledBy: EventSource ->
88+
meetingOrchestrator.scheduleMeeting(meeting, scheduledBy)
89+
}
90+
}
91+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package link.socket.kore.agents.events.meetings
2+
3+
import link.socket.kore.agents.events.EventSource
4+
5+
/**
6+
* Functional interface for scheduling meetings.
7+
*
8+
* This interface decouples the TicketOrchestrator from MeetingOrchestrator,
9+
* allowing them to be composed by a higher-level orchestrator without
10+
* direct dependencies. This enables bidirectional communication between
11+
* orchestrators through the parent EnvironmentOrchestrator.
12+
*/
13+
fun interface MeetingSchedulingService {
14+
/**
15+
* Schedule a meeting.
16+
*
17+
* @param meeting The meeting to schedule
18+
* @param scheduledBy The event source that is scheduling the meeting
19+
* @return Result containing the scheduled meeting with updated thread info
20+
*/
21+
suspend fun scheduleMeeting(
22+
meeting: Meeting,
23+
scheduledBy: EventSource,
24+
): Result<Meeting>
25+
}

shared/src/commonMain/kotlin/link/socket/kore/agents/events/tickets/TicketOrchestrator.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import link.socket.kore.agents.events.bus.EventBus
1212
import link.socket.kore.agents.events.meetings.Meeting
1313
import link.socket.kore.agents.events.meetings.MeetingId
1414
import link.socket.kore.agents.events.meetings.MeetingInvitation
15-
import link.socket.kore.agents.events.meetings.MeetingOrchestrator
15+
import link.socket.kore.agents.events.meetings.MeetingSchedulingService
1616
import link.socket.kore.agents.events.meetings.MeetingStatus
1717
import link.socket.kore.agents.events.meetings.MeetingType
1818
import link.socket.kore.agents.events.messages.AgentMessageApi
@@ -33,7 +33,7 @@ class TicketOrchestrator(
3333
private val ticketRepository: TicketRepository,
3434
private val eventBus: EventBus,
3535
private val messageApi: AgentMessageApi,
36-
private val meetingOrchestrator: MeetingOrchestrator,
36+
private val meetingSchedulingService: MeetingSchedulingService,
3737
private val logger: EventLogger = ConsoleEventLogger(),
3838
) {
3939

@@ -484,8 +484,8 @@ class TicketOrchestrator(
484484
),
485485
)
486486

487-
// Schedule the meeting using MeetingOrchestrator
488-
val meetingResult = meetingOrchestrator.scheduleMeeting(
487+
// Schedule the meeting using MeetingSchedulingService
488+
val meetingResult = meetingSchedulingService.scheduleMeeting(
489489
meeting = meeting,
490490
scheduledBy = EventSource.Agent(messageApi.agentId),
491491
)

shared/src/jvmTest/kotlin/link/socket/kore/agents/events/tickets/BacklogAnalyticsTest.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import link.socket.kore.agents.events.Database
1717
import link.socket.kore.agents.events.bus.EventBus
1818
import link.socket.kore.agents.events.meetings.MeetingOrchestrator
1919
import link.socket.kore.agents.events.meetings.MeetingRepository
20+
import link.socket.kore.agents.events.meetings.MeetingSchedulingService
2021
import link.socket.kore.agents.events.messages.AgentMessageApi
2122
import link.socket.kore.agents.events.messages.MessageRepository
2223
import link.socket.kore.data.DEFAULT_JSON
@@ -60,11 +61,16 @@ class BacklogAnalyticsTest {
6061
messageApi = messageApi,
6162
)
6263

64+
// Create a MeetingSchedulingService that delegates to the meetingOrchestrator
65+
val meetingSchedulingService = MeetingSchedulingService { meeting, scheduledBy ->
66+
meetingOrchestrator.scheduleMeeting(meeting, scheduledBy)
67+
}
68+
6369
ticketOrchestrator = TicketOrchestrator(
6470
ticketRepository = ticketRepository,
6571
eventBus = eventBus,
6672
messageApi = messageApi,
67-
meetingOrchestrator = meetingOrchestrator,
73+
meetingSchedulingService = meetingSchedulingService,
6874
)
6975
}
7076

shared/src/jvmTest/kotlin/link/socket/kore/agents/events/tickets/TicketBuilderTest.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import link.socket.kore.agents.events.Database
1919
import link.socket.kore.agents.events.bus.EventBus
2020
import link.socket.kore.agents.events.meetings.MeetingOrchestrator
2121
import link.socket.kore.agents.events.meetings.MeetingRepository
22+
import link.socket.kore.agents.events.meetings.MeetingSchedulingService
2223
import link.socket.kore.agents.events.messages.AgentMessageApi
2324
import link.socket.kore.agents.events.messages.MessageRepository
2425
import link.socket.kore.data.DEFAULT_JSON
@@ -61,11 +62,16 @@ class TicketBuilderTest {
6162
messageApi = messageApi,
6263
)
6364

65+
// Create a MeetingSchedulingService that delegates to the meetingOrchestrator
66+
val meetingSchedulingService = MeetingSchedulingService { meeting, scheduledBy ->
67+
meetingOrchestrator.scheduleMeeting(meeting, scheduledBy)
68+
}
69+
6470
ticketOrchestrator = TicketOrchestrator(
6571
ticketRepository = ticketRepository,
6672
eventBus = eventBus,
6773
messageApi = messageApi,
68-
meetingOrchestrator = meetingOrchestrator,
74+
meetingSchedulingService = meetingSchedulingService,
6975
)
7076
}
7177

shared/src/jvmTest/kotlin/link/socket/kore/agents/events/tickets/TicketMeetingIntegrationTest.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import link.socket.kore.agents.events.api.EventHandler
2222
import link.socket.kore.agents.events.bus.EventBus
2323
import link.socket.kore.agents.events.meetings.MeetingOrchestrator
2424
import link.socket.kore.agents.events.meetings.MeetingRepository
25+
import link.socket.kore.agents.events.meetings.MeetingSchedulingService
2526
import link.socket.kore.agents.events.messages.AgentMessageApi
2627
import link.socket.kore.agents.events.messages.MessageRepository
2728
import link.socket.kore.agents.events.tasks.AgendaItem
@@ -70,11 +71,16 @@ class TicketMeetingIntegrationTest {
7071
messageApi = messageApi,
7172
)
7273

74+
// Create a MeetingSchedulingService that delegates to the meetingOrchestrator
75+
val meetingSchedulingService = MeetingSchedulingService { meeting, scheduledBy ->
76+
meetingOrchestrator.scheduleMeeting(meeting, scheduledBy)
77+
}
78+
7379
ticketOrchestrator = TicketOrchestrator(
7480
ticketRepository = ticketRepository,
7581
eventBus = eventBus,
7682
messageApi = messageApi,
77-
meetingOrchestrator = meetingOrchestrator,
83+
meetingSchedulingService = meetingSchedulingService,
7884
)
7985

8086
// Subscribe to capture published events

shared/src/jvmTest/kotlin/link/socket/kore/agents/events/tickets/TicketOrchestratorTest.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import link.socket.kore.agents.events.api.EventHandler
2020
import link.socket.kore.agents.events.bus.EventBus
2121
import link.socket.kore.agents.events.meetings.MeetingOrchestrator
2222
import link.socket.kore.agents.events.meetings.MeetingRepository
23+
import link.socket.kore.agents.events.meetings.MeetingSchedulingService
2324
import link.socket.kore.agents.events.messages.AgentMessageApi
2425
import link.socket.kore.agents.events.messages.MessageRepository
2526
import link.socket.kore.data.DEFAULT_JSON
@@ -65,11 +66,16 @@ class TicketOrchestratorTest {
6566
messageApi = messageApi,
6667
)
6768

69+
// Create a MeetingSchedulingService that delegates to the meetingOrchestrator
70+
val meetingSchedulingService = MeetingSchedulingService { meeting, scheduledBy ->
71+
meetingOrchestrator.scheduleMeeting(meeting, scheduledBy)
72+
}
73+
6874
ticketOrchestrator = TicketOrchestrator(
6975
ticketRepository = ticketRepository,
7076
eventBus = eventBus,
7177
messageApi = messageApi,
72-
meetingOrchestrator = meetingOrchestrator,
78+
meetingSchedulingService = meetingSchedulingService,
7379
)
7480

7581
// Subscribe to capture published events

0 commit comments

Comments
 (0)