Create static and dynamic Server Jobs.
Constraints
You have created the project with scala-adapters-g8
Job Configuration
The jobs are configured in the reference.conf
, here from the scala-adapters
project.
```
job.configs = [{
ident = "demoJob"
schedule {
// the first time of day the Import should run (this is the Server time!). (format is HH : mm)
// Default is 01 : 00
first.time = "03:00"
// the first weekday if needed (e.g. to emulate once a week)
// possible : "monday" , "tuesday" , "wednesday" , "thursday" , "friday" , "saturday" , "sunday" or "-" for nothing
first.weekday = "tuesday"
// the period the Adapter should call the Coop Webservice
// Default is one day ( 1440 minutes) - be aware 1 minute is the smallest period possible
// - and it must be greater than the time the import takes!
// make also sure that the period is so that the import is at always the same time of day.
interval.minutes = 2
}
}, {
ident = "demoJobWithDefaultScheduler"
schedule {
}
}, {
ident = "demoJobWithoutScheduler"
}]
```
You see above the possible configurations (with- and without a Scheduler defined).
Each Job needs a unique ident!
Job Creation
You have to provide a Factory that creates the JobProcess vor a JobConfig.
Static Creation
Static creation means that the Jobs are created at Startup in the trait JobCreation
.
All you need to do shows the example from scala-adapters
```
// the Factory must be a Singleton
@Singleton
class DemoJobCreation @Inject ()( demoJob : DemoJobProcess // each JobProcess is injected
, demoJobWithDefaultScheduler : DemoJobWithDefaultSchedulerActor
, demoJobWithoutScheduler : DemoJobWithoutSchedulerActor
, @Named ( "actorSchedulers" ) val actorSchedulers : ActorRef // needed to create Schedules
, actorSystem : ActorSystem // needed to create the JobActors
)( implicit val ec : ExecutionContext ) // needed for async processing
extends JobCreation {
// create all JobActors
private lazy val demoJobRef = actorSystem . actorOf ( JobActor . props ( jobConfigs ( demoJobIdent ), demoJob ), demoJobIdent )
private lazy val demoJobWithDefaultSchedulerRef = actorSystem . actorOf ( JobActor . props ( jobConfigs ( demoJobWithDefaultSchedulerIdent ), demoJobWithDefaultScheduler ), demoJobWithDefaultSchedulerIdent )
private lazy val demoJobWithoutSchedulerRef = actorSystem . actorOf ( JobActor . props ( jobConfigs ( demoJobWithoutSchedulerIdent ), demoJobWithoutScheduler ), demoJobWithoutSchedulerIdent )
// return the correct JobActor for a JobConfig
def createJobActor ( jobConfig : JobConfig ) : ActorRef = jobConfig . jobIdent match {
case "demoJob" => demoJobRef
case "demoJobWithDefaultScheduler" => demoJobWithDefaultSchedulerRef
case "demoJobWithoutScheduler" => demoJobWithoutSchedulerRef
case other => throw ServiceException ( s "There is no Job for $other" )
}
}
```
Dynamic Creation
Dynamic creation means that the Jobs are created at Runtime in your Factory .
The example is from a Calendar integration, where different clients use different Service-URLs.
(only differences to static creation are explained)
```
@Singleton
class CalendarJobCreation @Inject ()( calendarImporter : CalendarImporter // the import infrastructure
, calendarService : CalendarService // the service to integrate
, @Named ( "actorSchedulers" ) val actorSchedulers : ActorRef
, actorSystem : ActorSystem
)( implicit val mat : Materializer
, val ec : ExecutionContext )
extends JobCreation {
def createJobActor ( jobConfig : JobConfig ) : ActorRef = create ( jobConfig )
private def create ( jobConfig : JobConfig ) : ActorRef = {
// creates a JobProcess from the JobConfig, that includes a subWebPath sent by the client.
val process = CalendarProcess ( jobConfig , calendarImporter , calendarService )
val jobActor = actorSystem . actorOf ( JobActor . props ( jobConfig , process ))
initSchedule ( jobConfig , jobActor )
jobActor
}
// return empty Map onStartUp - as the JobProcesses are created on the fly
override def createJobActorsOnStartUp () : Map [ JobConfig , ActorRef ] = Map ()
}
```
Job Process
Implements the Job logic itself, like:
Server Batch Jobs
Handling Client Requests
Implement Chat-Bot
etc.
Here the implementation you have in your get-started Project.
```
class GetStartedProcess @Inject ()()
( implicit val mat : Materializer , val ec : ExecutionContext )
extends JobProcess {
val jobLabel = "GetStarted Job"
def createInfo () : ProjectInfo = // check createInfo for adding more infos!
createInfo ( version . BuildInfo . version )
// the process fakes some long taking tasks that logs its progress
def runJob ( user : String )
( implicit logService : LogService
, jobActor : ActorRef ) : Future [ LogService ] = {
Future {
logService . startLogging ()
val results = ... // e.g. call a service
results . foreach ( doSomeWork )
logService // fluent api
}
}
protected def doSomeWork ( dr : GetStartedResult )
( implicit logService : LogService ) : LogEntry = {
...
logService . log ( ll , s "Job: $jobLabel $ll: ${dr.name}" , detail )
}
}
```
Register Factory
Now you have to tell Guice (Dependency Injection) what class is responsible for the Job creation.
In your get-started Project this already done in Module
.
```
class Module extends AbstractModule with AkkaGuiceSupport {
def configure () : Unit = {
bind ( classOf [ JobCreation ])
. to ( classOf [ GetStartedJobCreation ])
. asEagerSingleton () // make it eager - as the Job is static and created at startup
... // more configuration
}
}
```
Check the Result
Run the Project, as described here get-started::run
If you have only one Job , then http://localhost:9000 is all you need.
If you have more than one Job , you use http://localhost:9000/jobProcess/JOB_NAME
.
By default it takes the first Job of the configuration.