@@ -5,9 +5,11 @@ import akka.pattern.ask
5
5
import akka .util .Timeout
6
6
import de .upb .cs .swt .delphi .instanceregistry .Docker .DockerActor ._
7
7
import de .upb .cs .swt .delphi .instanceregistry .Docker .{DockerActor , DockerConnection }
8
+ import akka .stream .scaladsl .{Keep , Sink , Source }
9
+ import akka .stream .{ActorMaterializer , Materializer , OverflowStrategy }
8
10
import de .upb .cs .swt .delphi .instanceregistry .daos .{DynamicInstanceDAO , InstanceDAO }
9
11
import de .upb .cs .swt .delphi .instanceregistry .io .swagger .client .model .InstanceEnums .{ComponentType , InstanceState }
10
- import de .upb .cs .swt .delphi .instanceregistry .io .swagger .client .model .{ Instance , InstanceEnums }
12
+ import de .upb .cs .swt .delphi .instanceregistry .io .swagger .client .model ._
11
13
12
14
import scala .concurrent .duration ._
13
15
import scala .concurrent .{Await , ExecutionContext , Future }
@@ -17,13 +19,17 @@ import scala.util.{Failure, Success, Try}
17
19
class RequestHandler (configuration : Configuration , connection : DockerConnection ) extends AppLogging {
18
20
19
21
22
+
20
23
implicit val system : ActorSystem = Registry .system
24
+ implicit val materializer : Materializer = ActorMaterializer ()
21
25
implicit val ec : ExecutionContext = system.dispatcher
22
26
23
- val dockerActor : ActorRef = system.actorOf(DockerActor .props(connection))
24
-
25
27
private [instanceregistry] val instanceDao : InstanceDAO = new DynamicInstanceDAO (configuration)
26
28
29
+ val (eventActor, eventPublisher) = Source .actorRef[RegistryEvent ](0 , OverflowStrategy .dropNew)
30
+ .toMat(Sink .asPublisher(fanout = true ))(Keep .both)
31
+ .run()
32
+ val dockerActor : ActorRef = system.actorOf(DockerActor .props(connection))
27
33
28
34
def initialize (): Unit = {
29
35
log.info(" Initializing request handler..." )
@@ -35,7 +41,8 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
35
41
log.info(" Done initializing request handler." )
36
42
}
37
43
38
- def shutdown (): Unit = {
44
+ def shutdown () : Unit = {
45
+ eventActor ! PoisonPill
39
46
instanceDao.shutdown()
40
47
}
41
48
@@ -56,7 +63,10 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
56
63
dockerId = None , instanceState = InstanceState .Running )
57
64
58
65
instanceDao.addInstance(newInstance) match {
59
- case Success (_) => Success (newID)
66
+ case Success (_) =>
67
+ fireNumbersChangedEvent(newInstance.componentType)
68
+ fireInstanceAddedEvent(newInstance)
69
+ Success (newID)
60
70
case Failure (x) => Failure (x)
61
71
}
62
72
}
@@ -74,7 +84,10 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
74
84
} else if (isInstanceDockerContainer(instanceId)) {
75
85
OperationResult .IsDockerContainer
76
86
} else {
87
+ val instanceToRemove = instanceDao.getInstance(instanceId).get
88
+ fireInstanceRemovedEvent(instanceToRemove)
77
89
instanceDao.removeInstance(instanceId)
90
+ fireNumbersChangedEvent(instanceToRemove.componentType)
78
91
OperationResult .Ok
79
92
}
80
93
}
@@ -87,6 +100,10 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
87
100
instanceDao.allInstances().count(i => i.componentType == compType)
88
101
}
89
102
103
+ def getEventList (id : Long ) : Try [List [RegistryEvent ]] = {
104
+ instanceDao.getEventsFor(id)
105
+ }
106
+
90
107
def getMatchingInstanceOfType (compType : ComponentType ): Try [Instance ] = {
91
108
log.info(s " Trying to match to instance of type $compType ... " )
92
109
getNumberOfInstances(compType) match {
@@ -148,8 +165,10 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
148
165
instanceDao.addMatchingResult(id, result)
149
166
if (result && instance.instanceState == InstanceState .NotReachable ) {
150
167
instanceDao.setStateFor(instance.id.get, InstanceState .Running )
168
+ fireStateChangedEvent(instanceDao.getInstance(id).get)
151
169
} else if (! result && instance.instanceState == InstanceState .Running ) {
152
170
instanceDao.setStateFor(instance.id.get, InstanceState .NotReachable )
171
+ fireStateChangedEvent(instanceDao.getInstance(id).get)
153
172
}
154
173
log.info(s " Applied matching result $result to instance with id $id. " )
155
174
OperationResult .Ok
@@ -169,17 +188,20 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
169
188
deployResult match {
170
189
case Failure (ex) =>
171
190
log.error(s " Failed to deploy container, docker host not reachable. " )
191
+ fireDockerOperationErrorEvent(None , s " Deploy failed with message: ${ex.getMessage}" )
172
192
Failure (new RuntimeException (s " Failed to deploy container, docker host not reachable ( ${ex.getMessage}). " ))
173
193
case Success ((dockerId, host, port)) =>
174
194
val normalizedHost = host.substring(1 ,host.length - 1 )
175
195
log.info(s " Deployed new container with id $dockerId, host $normalizedHost and port $port. " )
176
196
177
- val newInstance = Instance (Some (newId), normalizedHost, port, name.getOrElse(s " Generic $componentType" ), componentType, Some (dockerId), InstanceState .Stopped )
197
+ val newInstance = Instance (Some (newId), normalizedHost, port, name.getOrElse(s " Generic $componentType" ), componentType, Some (dockerId), InstanceState .Deploying )
178
198
log.info(s " Registering instance $newInstance.... " )
179
199
180
200
instanceDao.addInstance(newInstance) match {
181
201
case Success (_) =>
182
202
log.info(" Successfully registered." )
203
+ fireInstanceAddedEvent(newInstance)
204
+ fireNumbersChangedEvent(newInstance.componentType)
183
205
Success (newId)
184
206
case Failure (x) =>
185
207
log.info(s " Failed to register. Exception: $x" )
@@ -213,6 +235,7 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
213
235
instanceDao.setStateFor(instance.id.get, InstanceState .Running )
214
236
}
215
237
log.info(s " Instance with id $id has reported start. " )
238
+ fireStateChangedEvent(instanceDao.getInstance(id).get)
216
239
OperationResult .Ok
217
240
}
218
241
}
@@ -245,6 +268,7 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
245
268
instanceDao.setStateFor(instance.id.get, InstanceState .NotReachable )
246
269
}
247
270
log.info(s " Instance with id $id has reported stop. " )
271
+ fireStateChangedEvent(instanceDao.getInstance(id).get)
248
272
OperationResult .Ok
249
273
}
250
274
}
@@ -277,6 +301,7 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
277
301
instanceDao.setStateFor(instance.id.get, InstanceState .Failed )
278
302
}
279
303
log.info(s " Instance with id $id has reported failure. " )
304
+ fireStateChangedEvent(instanceDao.getInstance(id).get)
280
305
OperationResult .Ok
281
306
}
282
307
@@ -303,9 +328,11 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
303
328
(dockerActor ? pause(instance.dockerId.get)).map{
304
329
_ => log.info(s " Instance $id paused. " )
305
330
instanceDao.setStateFor(instance.id.get, InstanceState .Paused )
331
+ fireStateChangedEvent(instanceDao.getInstance(id).get)
306
332
}.recover {
307
333
case ex : Exception =>
308
334
log.warning(s " Failed to pause container with id $id. Message is: ${ex.getMessage}" )
335
+ fireDockerOperationErrorEvent(Some (instance), s " Pause failed with message: ${ex.getMessage}" )
309
336
}
310
337
311
338
OperationResult .Ok
@@ -336,9 +363,11 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
336
363
(dockerActor ? unpause(instance.dockerId.get)).map{
337
364
_ => log.info(s " Instance $id resumed. " )
338
365
instanceDao.setStateFor(instance.id.get, InstanceState .Running )
366
+ fireStateChangedEvent(instanceDao.getInstance(id).get)
339
367
}.recover {
340
368
case ex : Exception =>
341
369
log.warning(s " Failed to resume container with id $id. Message is: ${ex.getMessage}" )
370
+ fireDockerOperationErrorEvent(Some (instance), s " Resume failed with message: ${ex.getMessage}" )
342
371
}
343
372
344
373
OperationResult .Ok
@@ -371,9 +400,11 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
371
400
(dockerActor ? stop(instance.dockerId.get)).map{
372
401
_ => log.info(s " Instance $id stopped. " )
373
402
instanceDao.setStateFor(instance.id.get, InstanceState .Stopped )
403
+ fireStateChangedEvent(instance)
374
404
}.recover {
375
405
case ex : Exception =>
376
406
log.warning(s " Failed to stop container with id $id. Message is: ${ex.getMessage}" )
407
+ fireDockerOperationErrorEvent(Some (instance), s " Stop failed with message: ${ex.getMessage}" )
377
408
}
378
409
379
410
OperationResult .Ok
@@ -405,6 +436,7 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
405
436
}.recover {
406
437
case ex : Exception =>
407
438
log.warning(s " Failed to start container with id $id. Message is: ${ex.getMessage}" )
439
+ fireDockerOperationErrorEvent(Some (instance), s " Start failed with message: ${ex.getMessage}" )
408
440
}
409
441
410
442
OperationResult .Ok
@@ -436,15 +468,18 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
436
468
437
469
(dockerActor ? delete(instance.dockerId.get)).map{
438
470
_ => log.info(s " Container for instance $id deleted. " )
439
- instanceDao.setStateFor(instance.id.get, InstanceState .Stopped )
440
471
}.recover {
441
472
case ex : Exception =>
442
473
log.warning(s " Failed to delete container for instance with id $id. Message is: ${ex.getMessage}" )
474
+ fireDockerOperationErrorEvent(Some (instance), s " Delete failed with message: ${ex.getMessage}" )
443
475
}
444
476
445
477
// Delete data either way
446
478
instanceDao.removeInstance(id) match {
447
- case Success (_) => OperationResult .Ok
479
+ case Success (_) =>
480
+ fireNumbersChangedEvent(instance.componentType)
481
+ fireInstanceRemovedEvent(instance)
482
+ OperationResult .Ok
448
483
case Failure (_) => OperationResult .InternalError
449
484
}
450
485
} else {
@@ -462,7 +497,7 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
462
497
instanceDao.getInstance(id)
463
498
}
464
499
465
- def instanceHasState (id : Long , state : InstanceEnums . State ): Boolean = {
500
+ def instanceHasState (id : Long , state : InstanceState ): Boolean = {
466
501
instanceDao.getInstance(id) match {
467
502
case Some (instance) => instance.instanceState == state
468
503
case None => false
@@ -473,6 +508,36 @@ class RequestHandler(configuration: Configuration, connection: DockerConnection)
473
508
instanceDao.getDockerIdFor(id).isSuccess
474
509
}
475
510
511
+ private def fireNumbersChangedEvent (componentType : ComponentType ): Unit = {
512
+ val newNumber = instanceDao.getInstancesOfType(componentType).size
513
+ eventActor ! RegistryEventFactory .createNumbersChangedEvent(componentType, newNumber)
514
+ }
515
+
516
+ private def fireInstanceAddedEvent (addedInstance : Instance ): Unit = {
517
+ val event = RegistryEventFactory .createInstanceAddedEvent(addedInstance)
518
+ eventActor ! event
519
+ instanceDao.addEventFor(addedInstance.id.get, event)
520
+ }
521
+
522
+ private def fireInstanceRemovedEvent (removedInstance : Instance ): Unit = {
523
+ // Do not add removed event, instance will not be present in DAO anymore
524
+ eventActor ! RegistryEventFactory .createInstanceRemovedEvent(removedInstance)
525
+ }
526
+
527
+ private def fireStateChangedEvent (updatedInstance : Instance ): Unit = {
528
+ val event = RegistryEventFactory .createStateChangedEvent(updatedInstance)
529
+ eventActor ! event
530
+ instanceDao.addEventFor(updatedInstance.id.get, event)
531
+ }
532
+
533
+ private def fireDockerOperationErrorEvent (affectedInstance : Option [Instance ], errorMessage : String ): Unit = {
534
+ val event = RegistryEventFactory .createDockerOperationErrorEvent(affectedInstance, errorMessage)
535
+ eventActor ! event
536
+ if (affectedInstance.isDefined){
537
+ instanceDao.addEventFor(affectedInstance.get.id.get, event)
538
+ }
539
+ }
540
+
476
541
private def countConsecutivePositiveMatchingResults (id : Long ): Int = {
477
542
if (! instanceDao.hasInstance(id) || instanceDao.getMatchingResultsFor(id).get.isEmpty) {
478
543
0
0 commit comments