github.com/Axway/agent-sdk@v1.1.101/pkg/jobs/README.md (about)

     1  # SDK Jobs
     2  
     3  The jobs library is used to coordinate tasks that run within an agent.  There are 4 job types, explained below, that may be used.  Single run, Retry, Interval, and Scheduled jobs.
     4  
     5  The jobs library keeps track of all jobs that are registered and executes them appropriately.  Scheduled and Interval jobs are continuous jobs that execute more than once.  These
     6  jobs are continuously executed according to their settings.  If any of these continuous jobs begin to fail the library will pause execution of all jobs until a running status is  
     7  achieved again.
     8  
     9  When using the jobs library, remember that the main process of the agent can not exit, otherwise all jobs will exit
    10  
    11  ## Job status
    12  
    13  The following are the possible job status values that can be returned by the GetJobStatus method
    14  
    15  | Status       | Definition                                                                              |
    16  |--------------|-----------------------------------------------------------------------------------------|
    17  | Initializing | Returned when the has been created but not yet started                                  |
    18  | Running      | Returned when a job is being executed, or between executions in a working state         |
    19  | Retrying     | Returned only for retry job types that return an error in a call to Execute             |
    20  | Stopped      | Returned when a continuous job is in a non-working state and is waiting to be restarted |
    21  | Failed       | Returned when a single run or retry job does not Execute without error                  |
    22  | Finished     | Returned when a single run or retry job Executes properly                               |
    23  
    24  ## Implementing the job interface
    25  
    26  Before registering a job, the Job interface has to be implemented for your job
    27  
    28  ```go
    29  package main
    30  
    31  import (
    32    github.com/Axway/agent-sdk/pkg/jobs
    33  )
    34  
    35  type MyJob struct {
    36    jobs.Job // implements interface
    37  }
    38  
    39  func (j *MyJob) Status() error {
    40    // continually called determining the status of any dependencies for the job
    41    // returning an error means the job should not be executed
    42  }
    43  
    44  func (j *MyJob) Ready() bool {
    45    // called prior to executing the job the first time
    46    // return true when the job can begin execution, false otherwise
    47  }
    48  
    49  func (j *MyJob) Execute() error {
    50    // called each time the job should be executed
    51    // returning an error stops continuous jobs from executing
    52  }
    53  ```
    54  
    55  ## Job types
    56  
    57  The section covers the following job types
    58  
    59  - [Single run jobs](#single-run-jobs)
    60  - [Retry jobs](#retry-jobs)
    61  - [Interval jobs](#interval-jobs)
    62  - [Detached interval jobs](#detached-interval-jobs)
    63  - [Scheduled jobs](#scheduled-jobs)
    64  - [Channel jobs](#channel-jobs)
    65  
    66  ### Single run jobs
    67  
    68  Single run jobs are used to run a specific task exactly once, regardless of pass or fail.
    69  
    70  #### Register Single run job
    71  
    72  Register the job and get its status
    73  
    74  ```go
    75  package main
    76  
    77  import (
    78    "fmt"
    79  
    80    "github.com/Axway/agent-sdk/pkg/jobs"
    81  )
    82  
    83  func main() {
    84    myJob := MyJob{}
    85    jobID, err := jobs.RegisterSingleRunJobWithName(myJob, "My Job")
    86    if err != nil {
    87      panic(err) // error registering the job
    88    }
    89    fmt.Println(GetJobStatus(jobID))
    90  }
    91  ```
    92  
    93  ### Retry jobs
    94  
    95  Retry jobs are like single run jobs, but are allowed to retry a specified number of times before failing
    96  
    97  #### Register Retry job
    98  
    99  Register the job and get its status
   100  
   101  ```go
   102  package main
   103  
   104  import (
   105    "fmt"
   106  
   107    "github.com/Axway/agent-sdk/pkg/jobs"
   108  )
   109  
   110  func main() {
   111    myJob := MyJob{}
   112    retries := 3
   113    jobID, err := jobs.RegisterRetryJobWithName(myJob, retries, "My Job")
   114    if err != nil {
   115      panic(err) // error registering the job
   116    }
   117    fmt.Println(GetJobStatus(jobID))
   118  }
   119  ```
   120  
   121  ### Interval jobs
   122  
   123  Interval jobs are executed with a certain time duration between the end of one execution to the beginning of the next
   124  
   125  #### Register Interval job
   126  
   127  Register the job and get its status
   128  
   129  ```go
   130  package main
   131  
   132  import (
   133    "fmt"
   134  
   135    "github.com/Axway/agent-sdk/pkg/jobs"
   136  )
   137  
   138  func main() {
   139    myJob := MyJob{}
   140    interval := 30 * time.Second
   141    jobID, err := jobs.RegisterIntervalJobWithName(myJob, interval, "My Job")
   142    if err != nil {
   143      panic(err) // error registering the job
   144    }
   145    fmt.Println(GetJobStatus(jobID))
   146  }
   147  ```
   148  
   149  ### Detached interval jobs
   150  
   151  Detached interval jobs are just like Interval jobs except they are not stopped with other jobs fail, they run independent of the job pool
   152  
   153  ### Scheduled jobs
   154  
   155  Scheduled jobs are executed on a certain time frame, the previous execution has to end prior to the next execution starting.
   156  
   157  #### Defining a schedule
   158  
   159  Scheduled jobs use a cronjob expressions to set up their schedule.  The fields are Seconds, Minutes, Hours, Day of month, Month,
   160  Day of week, and Year.  There are also predefined expressions that may be used.
   161  
   162  Cron expressions are defined with the above fields in a single string each field value separated by a space.
   163  
   164  Allowed values
   165  
   166  | Seconds | Minutes | Hour   | Day of month | Month  | Day of week | Year        |
   167  |---------|---------|--------|--------------|--------|-------------|-------------|
   168  | 0 - 59  | 0 - 59  | 0 - 23 | 1 - 31       | 1 - 12 | 0 - 6       | 1970 - 2099 |
   169  
   170  All of the fields can also utilize the following characters within their schedule
   171  
   172  - Asterick (*) - matches all values for this field
   173  - Slash (/) - describes increments steps within the field
   174  - Comma (,) - separates values within the field to match
   175  - Hyphen (-) - defines a range of values within the field to match
   176  
   177  Examples
   178  
   179  | Expression                  | Description                                                                           |
   180  |-----------------------------|---------------------------------------------------------------------------------------|
   181  | \* \* \* \* \* \* \*        | Run every second                                                                      |
   182  | 30 5-59/15 \* \* \* \* \*   | Run 30 seconds past the minute, starting at minute 5 and every 15 minutes there after |
   183  | 0 0 1,5,9,15,21 \* \* \* \* | Run at hour 1, 5, 9, 15, and 21 of each day                                           |
   184  | 0 0 0 \* \* 6 \*            | Run at midnight every Saturday                                                        |
   185  
   186  Predefined expressions
   187  
   188  | Expression | Description                                 | Equivalent         |
   189  |------------|---------------------------------------------|--------------------|
   190  | @hourly    | Run at the top of the hour                  | 0 0 \* \* \* \* \* |
   191  | @daily     | Run at midnight every day                   | 0 0 0 \* \* \* \*  |
   192  | @weekly    | Run at midnight on Sundays                  | 0 0 0 \* \* 0 \*   |
   193  | @monthly   | Run at midnight on the first of every month | 0 0 0 1 \* \* \*   |
   194  
   195  #### Register Scheduled job
   196  
   197  Register the job and get its status
   198  
   199  ```go
   200  package main
   201  
   202  import (
   203    "fmt"
   204  
   205    "github.com/Axway/agent-sdk/pkg/jobs"
   206  )
   207  
   208  func main() {
   209    myJob := MyJob{}
   210    runHalfPastHour := "0 30 * * * * *"
   211    jobID, err := jobs.RegisterScheduledJobWithName(myJob, runHalfPastHour, "My Job")
   212    if err != nil {
   213      panic(err) // error registering the job
   214    }
   215    fmt.Println(GetJobStatus(jobID))
   216  }
   217  ```
   218  
   219  ### Channel jobs
   220  
   221  Channel jobs are executed a single time via a go routine.  It is expected that the channel job runs forever.  
   222  
   223  To allow this job to be stopped and started the implementer will provide a channel that the jobs pool can use to tell the job to stop.
   224  
   225  #### Channel job implementation example
   226  
   227  ```go
   228  package myjob
   229  
   230  import "github.com/Axway/agent-sdk/pkg/jobs"
   231  
   232  type MyJob struct {
   233    jobs.Job
   234    workChannel chan interface{}
   235    stopChannel chan interface{}
   236  }
   237  
   238  func NewMyJob(stopChannel chan interface{}) *MyJob {
   239    return &MyJob{
   240      stopChannel: stopChannel,
   241      workChannel: make(chan interface{}),
   242    }
   243  }
   244  
   245  func (m *MyJob) Ready() bool {
   246    // validate all dependencies are ready
   247    return true
   248  }
   249  
   250  func (m *MyJob) Status() error {
   251    // check that the job is still running without error
   252    return nil
   253  }
   254  
   255  func (m *MyJob) Execute() error {
   256    for {
   257      select {
   258      case <-m.stopChannel:
   259        //stop the job
   260        return nil
   261      case msg := <-workChannel:
   262        //do work on msg
   263    }
   264    }
   265  }
   266  
   267  ```
   268  
   269  #### Register Channel job
   270  
   271  Register the job and get its status
   272  
   273  ```go
   274  package main
   275  
   276  import (
   277    "fmt"
   278  
   279    "github.com/Axway/agent-sdk/pkg/jobs"
   280  )
   281  
   282  func main() {
   283    stopChannel := make(chan interface{})
   284    myJob := NewMyJob(stopChannel)
   285    jobID, err := jobs.RegisterChannelJobWithName(myJob, stopChannel, "My Job")
   286    if err != nil {
   287      panic(err) // error registering the job
   288    }
   289    fmt.Println(GetJobStatus(jobID))
   290  }
   291  ```
   292  
   293  ## Job locks
   294  
   295  All continuous jobs (Interval and Scheduled) create locks that the agent can use to prevent the job from running at the same time as another process or job.
   296  The job will lock itself prior to calling its Execute function and unlock itself after Execute has finished
   297  
   298  Here is an example of how to create 2 jobs that can not execute at the same time.
   299  
   300  ```go
   301  package main
   302  
   303  import (
   304    github.com/Axway/agent-sdk/pkg/jobs
   305  )
   306  
   307  type FirstJob struct {
   308    jobs.Job // implements interface
   309  }
   310  
   311  func (j *FirstJob) Status() error {
   312    ...
   313  }
   314  
   315  func (j *FirstJob) Ready() bool {
   316    ...
   317  }
   318  
   319  func (j *FirstJob) Execute() error {
   320    ...
   321  }
   322  
   323  type SecondJob struct {
   324    jobs.Job // implements interface
   325    firstJobID string
   326  }
   327  
   328  func (j *SecondJob) Status() error {
   329    ...
   330  }
   331  
   332  func (j *SecondJob) Ready() bool {
   333    ...
   334  }
   335  
   336  func (j *SecondJob) Execute() error {
   337    jobs.JobLock(j.firstJobID)
   338    defer jobs.JobUnlock(j.firstJobID)
   339    ...
   340  }
   341  
   342  func main() {
   343    myFirstJob := FirstJob{}
   344    jobID, err := jobs.RegisterIntervalJob(myFirstJob, 30 * time.Second)
   345    if err != nil {
   346      panic(err) // error registering the job
   347    }
   348  
   349    mySecondJob := jobID{
   350      firstJobID: jobID,
   351    }
   352    _, err := jobs.RegisterIntervalJob(mySecondJob, 30 * time.Second)
   353    if err != nil {
   354      panic(err) // error registering the job
   355    }
   356  }
   357  ```