Skip to content

MultiStepsJobPlugin

Marco BARNIG edited this page Jan 17, 2020 · 3 revisions

Welcome to our tutorial lesson 14 concerning the development of Orthanc plugins. In this lesson we enhance the OneStepJobPlugin, developed in lesson 13, to execute multiple steps. To simulate the behavior of tasks doing hard work for a long time, we put the task in sleep mode during 10 seconds in each step. To simulate an error arriving during the execution of a real task, we generate a random number between 1 and 100 in each step. When the number exceeds a defined threshold, we throw a failure message.

MyJob.h

In the MyJob.h header file we add two private member variables to the class MyJob:

  • float counter_
  • float maxSteps_

We initialize the counter_ with zero and increment it in each step. If the counter_ equals the maxSteps_ limit, the job is finished and stopped with a success message.

To generate the random number, we add an additional public method bool RandomGenerator() to the class.

Here is the complete code of the MyJob.h header file.

#pragma once
#include <string>
#include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>

class MyJob : public OrthancPlugins::OrthancJob {
  std::string jobName_;
  float counter_;
  float maxSteps_;

  public:

  explicit MyJob(std::string jobType);

  ~MyJob();

  OrthancPluginJobStepStatus Step();
  void Stop(OrthancPluginJobStopReason reason);
  void Reset();
  bool RandomGenerator();
};

MyJob.cpp

The MyJob.cpp file of the MultiStepsJobPlugin contains more stuff than the corresponding file in the OneStepJobPlugin.

We must include additional libraries to implement the random and sleep features. In the MyJob constructor we must initialise the variables counter_ and maxSteps_. We set the steps limit to 10.

In the Step() function we check the value of the counter_. If it equals maxSteps_, we reset the counter_ to 0, update the job progress indicator with 1.0 and terminate the job with success. If it equals zero, we initialise the random seed.

The RandomGenerator() function is called and returns a boolean OK = true value if the generated randon number is lower than 94. If true, the counter_ is incremented, the progress indicator is updated with the fraction counter_ / maxSteps_ and the job is continued. If false, the job is terminated with a failure message.

The Stop() function provides the reason for a job termination. Two reasons are obvious: success or failure. But a multisteps job, which takes some time, can be paused or cancelled. These are two additional stop reasons.

The following panel presents the whole code of the MyJob.cpp file.

#include <Plugins/Samples/Common/OrthancPluginCppWrapper.h>
#include <Core/Toolbox.h>
#include <Core/Logging.h>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
#include <string>
#include <thread>
#include "MyJob.h"

// constructor
MyJob::MyJob(std::string jobType)
:
OrthancPlugins::OrthancJob(jobType),
jobName_(jobType),
counter_(0.0),
maxSteps_(10.0) {
  LOG(INFO) << "*** MyJob " << jobName_ << " constructor";
}

// destructor
MyJob::~MyJob() {
  LOG(INFO) << "*** MyJob destructor";
}

OrthancPluginJobStepStatus MyJob::Step() {
  if (MyJob::counter_ == MyJob::maxSteps_) {
     MyJob::counter_ = 0;
     MyJob::UpdateProgress(1.0);
     Json::Value detailInfo;
     detailInfo = Json::objectValue;
     detailInfo["Project"] = "RadioLogic Tutorial MultipleStepsJob";
     detailInfo["Author"] = "Marco Barnig";
     MyJob::UpdateContent(detailInfo);
     LOG(INFO) << "*** MyJob " << MyJob::jobName_ << " Step() Success";
     return OrthancPluginJobStepStatus_Success;
  } else {
  if (MyJob::counter_ == 0) {
    MyJob::UpdateProgress(0.0);
    // initialize random seed
    srand(time(0));
    }
    bool ok = MyJob::RandomGenerator();
    if (ok == true) {
      MyJob::counter_++;
      MyJob::UpdateProgress(MyJob::counter_ / MyJob::maxSteps_);
      LOG(INFO) << "*** MyJob " << MyJob::jobName_ << " Step() Continue";
      return OrthancPluginJobStepStatus_Continue;
    } else {
      LOG(INFO) << "*** MyJob " << MyJob::jobName_ << " Step() Failure";
      return OrthancPluginJobStepStatus_Failure;
    }
  }
}

void MyJob::Stop(OrthancPluginJobStopReason reason) {
  switch (reason) {
    case OrthancPluginJobStopReason_Success :
    LOG(INFO) << "*** MyJob " << MyJob::jobName_ << " Stop() Success";
    break;
    case OrthancPluginJobStopReason_Paused :
    LOG(INFO) << "*** MyJob " << MyJob::jobName_  << " Stop() Pause";
    break;
    case OrthancPluginJobStopReason_Failure :
    LOG(INFO) << "*** MyJob " << MyJob::jobName_  << " Stop() Failure";
    break;
    case OrthancPluginJobStopReason_Canceled :
    LOG(INFO) << "*** MyJob " << MyJob::jobName_ << " Stop() Cancel";
    break;
    default :
    LOG(INFO) << "*** Job-Error: " << MyJob::jobName_ << " the stop-reason is out of enum range";
  }
}

void MyJob::Reset() {
  LOG(INFO) << "*** MyJob " << MyJob::jobName_ << " Reset()";
}

bool MyJob::RandomGenerator() {
  std::this_thread::sleep_for(std::chrono::seconds(10));
  // generate random number between 1 and 100
  int randomNumber = rand() % 100;
  LOG(INFO) << "*** Random Number: " << randomNumber;
  if (randomNumber > 94) {
    return false;
  } else {
    return true;
  }
}

MultiStepsJobPlugin.cpp

The MultiStepsJobPlugin.cpp is virtually identical to the OneStepJobPlugin.cpp. The only differences are the name of the job (MultiStepsJob) and the callback URL /start-multiple-steps-job.

CMakeLists.txt

Except the names, the CMakeLists.txt is identical to the same file of the OneStepJobPlugin.

Building and Testing

After 15 lessons, building and installing a plugin in the RadioLogicArchive has become a routine. Pointing the browser to the relative URL /start-multiple-steps-job displays the following webpage:

multiple-steps-job-1

The Jobs webpage lists our job now in the panel of the currently running jobs.

multiple-steps-job-2

If we click inside the job panel, the general information about the job is shown, together with a Pause job and a Cancel job button.

multiple-steps-job-3

Clicking the Pause job button, the job is moved inside the pending jobs panel with the tag paused.

multiple-steps-job-4

Another click displays a panel with a Resume job button to continue the job.

multiple-steps-job-5

The next two figures show the inactive job panel with the successfully completed job and the panel with the general and detailed information about the job.

multiple-steps-job-6

multiple-steps-job-7

The runtime of the completed job is indicated as 100 seconds. The job was taken ten times a sleep for 10 seconds. That makes a total of 100 seconds. Awesome:

A job terminated with failure is shown in the next figure.

multiple-steps-job-8

A failed job can be resubmitted in the general information panel. This works only for soft errors (for example temporary connection problems or transmission errors). Hard errors, caused by wrong filenames or missing data, can't be recovered. Our simulated failure with a random generator is a sort of soft error. Resubmitting our job has great chance to be successful. The job will continue at the step where it failed.

multiple-steps-job-9

Conclusions

This time we don't want to explore the log files because there will be nothing new to discover. We keep all our energy for the next lesson. Be curious!

Clone this wiki locally