11package cqrs
22
33import (
4- "log"
54 "reflect"
65 "time"
7-
8- "github.com/pborman/uuid"
96)
107
118// Command represents an actor intention to alter the state of the system
@@ -20,39 +17,60 @@ type Command struct {
2017// CreateCommand is a helper for creating a new command object with populated default properties
2118func CreateCommand (body interface {}) Command {
2219 commandType := reflect .TypeOf (body )
23- return Command {uuid .New (), uuid .New (), commandType .String (), time .Now (), body }
20+ return Command {MessageID : "mid:" + NewUUIDString (),
21+ CorrelationID : "cid:" + NewUUIDString (),
22+ CommandType : commandType .String (),
23+ Created : time .Now (),
24+
25+ Body : body }
2426}
2527
2628// CreateCommandWithCorrelationID is a helper for creating a new command object with populated default properties
2729func CreateCommandWithCorrelationID (body interface {}, correlationID string ) Command {
2830 commandType := reflect .TypeOf (body )
29- return Command {uuid .New (), correlationID , commandType .String (), time .Now (), body }
31+ return Command {MessageID : "mid:" + NewUUIDString (),
32+ CorrelationID : correlationID ,
33+ CommandType : commandType .String (),
34+ Created : time .Now (),
35+ Body : body }
3036}
3137
3238// CommandPublisher is responsilbe for publishing commands
3339type CommandPublisher interface {
34- Publish ( Command ) error
40+ PublishCommands ([] Command ) error
3541}
3642
3743// CommandReceiver is responsible for receiving commands
3844type CommandReceiver interface {
3945 ReceiveCommands (CommandReceiverOptions ) error
4046}
4147
48+ // CommandBus ...
49+ type CommandBus interface {
50+ CommandReceiver
51+ CommandPublisher
52+ }
53+
4254// CommandDispatchManager is responsible for coordinating receiving messages from command receivers and dispatching them to the command dispatcher.
4355type CommandDispatchManager struct {
4456 commandDispatcher * MapBasedCommandDispatcher
4557 typeRegistry TypeRegistry
4658 receiver CommandReceiver
4759}
4860
61+ // CommandDispatcher the internal command dispatcher
62+ func (m * CommandDispatchManager ) CommandDispatcher () CommandDispatcher {
63+ return m .commandDispatcher
64+ }
65+
4966// CommandReceiverOptions is an initalization structure to communicate to and from a command receiver go routine
5067type CommandReceiverOptions struct {
5168 TypeRegistry TypeRegistry
5269 Close chan chan error
5370 Error chan error
54- ReceiveCommand chan CommandTransactedAccept
71+ ReceiveCommand CommandHandler
5572 Exclusive bool
73+ ListenerCount int
5674}
5775
5876// CommandTransactedAccept is the message routed from a command receiver to the command manager.
@@ -106,17 +124,21 @@ func (m *MapBasedCommandDispatcher) DispatchCommand(command Command) error {
106124 if handlers , ok := m .registry [bodyType ]; ok {
107125 for _ , handler := range handlers {
108126 if err := handler (command ); err != nil {
127+ metricsCommandsFailed .WithLabelValues (command .CommandType ).Inc ()
109128 return err
110129 }
111130 }
112131 }
113132
114133 for _ , handler := range m .globalHandlers {
115134 if err := handler (command ); err != nil {
135+ metricsCommandsFailed .WithLabelValues (command .CommandType ).Inc ()
116136 return err
117137 }
118138 }
119139
140+ metricsCommandsDispatched .WithLabelValues (command .CommandType ).Inc ()
141+
120142 return nil
121143}
122144
@@ -137,46 +159,48 @@ func (m *CommandDispatchManager) RegisterGlobalHandler(handler CommandHandler) {
137159}
138160
139161// Listen starts a listen loop processing channels related to new incoming events, errors and stop listening requests
140- func (m * CommandDispatchManager ) Listen (stop <- chan bool , exclusive bool ) error {
162+ func (m * CommandDispatchManager ) Listen (stop <- chan bool , exclusive bool , listenerCount int ) error {
141163 // Create communication channels
142164 //
143165 // for closing the queue listener,
144166 closeChannel := make (chan chan error )
145167 // receiving errors from the listener thread (go routine)
146168 errorChannel := make (chan error )
147- // and receiving commands from the queue
148- receiveCommandChannel := make (chan CommandTransactedAccept )
169+
170+ // Command received channel receives a result with a channel to respond to, signifying successful processing of the message.
171+ // This should eventually call a command handler. See cqrs.NewVersionedCommandDispatcher()
172+ receiveCommandHandler := func (command Command ) error {
173+ PackageLogger ().Debugf ("CommandDispatchManager.DispatchCommand: %v" , command .CorrelationID )
174+ err := m .commandDispatcher .DispatchCommand (command )
175+ if err != nil {
176+ PackageLogger ().Debugf ("Error dispatching command: %v" , err )
177+ }
178+
179+ return err
180+ }
149181
150182 // Start receiving commands by passing these channels to the worker thread (go routine)
151- options := CommandReceiverOptions {m .typeRegistry , closeChannel , errorChannel , receiveCommandChannel , exclusive }
183+ options := CommandReceiverOptions {m .typeRegistry , closeChannel , errorChannel , receiveCommandHandler , exclusive , listenerCount }
152184 if err := m .receiver .ReceiveCommands (options ); err != nil {
153185 return err
154186 }
187+ go func () {
188+ for {
189+ // Wait on multiple channels using the select control flow.
190+ select {
191+ case <- stop :
192+ PackageLogger ().Debugf ("CommandDispatchManager.Stopping" )
193+ closeSignal := make (chan error )
194+ closeChannel <- closeSignal
195+ PackageLogger ().Debugf ("CommandDispatchManager.Stopped" )
196+ <- closeSignal
197+ // Receiving on this channel signifys an error has occured worker processor side
198+ case err := <- errorChannel :
199+ PackageLogger ().Debugf ("CommandDispatchManager.ErrorReceived: %s" , err )
155200
156- for {
157- // Wait on multiple channels using the select control flow.
158- select {
159- // Command received channel receives a result with a channel to respond to, signifying successful processing of the message.
160- // This should eventually call a command handler. See cqrs.NewVersionedCommandDispatcher()
161- case command := <- receiveCommandChannel :
162- log .Println ("CommandDispatchManager.DispatchCommand: " , command .Command )
163- if err := m .commandDispatcher .DispatchCommand (command .Command ); err != nil {
164- log .Println ("Error dispatching command: " , err )
165- command .ProcessedSuccessfully <- false
166- } else {
167- command .ProcessedSuccessfully <- true
168- log .Println ("CommandDispatchManager.DispatchSuccessful" )
169201 }
170- case <- stop :
171- log .Println ("CommandDispatchManager.Stopping" )
172- closeSignal := make (chan error )
173- closeChannel <- closeSignal
174- defer log .Println ("CommandDispatchManager.Stopped" )
175- return <- closeSignal
176- // Receiving on this channel signifys an error has occured worker processor side
177- case err := <- errorChannel :
178- log .Println ("CommandDispatchManager.ErrorReceived: " , err )
179- return err
180202 }
181- }
203+ }()
204+
205+ return nil
182206}
0 commit comments