{
  "version": "1.8.2",
  "timeZone": "Europe/Berlin",
  "title": "Example of a cancellable subprocess with live output logging.",
  "orderPreparation": {
    "parameters": {
      "executable_path": {
        "type": "String",
        "message": "/usr/bin/python3"
      },
      "script_path": {
        "type": "String",
        "message": "/home/user/script.py"
      }
    },
    "allowUndeclared": false
  },
  "instructions": [
    {
      "TYPE": "Execute.Named",
      "jobName": "cancellable_subprocess",
      "label": "cancellable_subprocess"
    }
  ],
  "jobs": {
    "cancellable_subprocess": {
      "agentName": "testAgent",
      "withSubagentClusterIdExpr": false,
      "executable": {
        "TYPE": "InternalExecutable",
        "internalType": "Python_Graal",
        "script": "import os\nimport subprocess\nimport threading\n\n##!include Python-ManagedProcessClass\nclass JS7Job(js7.Job):\n    def processOrder(self, js7Step):\n        # Reads the workflow arguments\n        executable_path = js7Step.getAllArgumentsAsNameValueMap().get(\"executable_path\") # e. g. '/usr/bin/python3', '/bin/sh'\n        script_path = js7Step.getAllArgumentsAsNameValueMap().get(\"script_path\") # e. g. '/home/user/script.py', '/script.sh'\n\n        # Creates the base command\n        cmd = [executable_path]\n\n        # Gets the last path entry and sets unbuffered mode only for Python\n        if os.path.basename(executable_path).startswith(\"python\"):\n            cmd.append(\"-u\")\n            \n        cmd.append(script_path)\n\n        # Adds arguments that will be passed to the application or script\n        cmd += [\"js7Step_argument_1\", \"js7Step_argument_2\"]\n\n        js7Step.getLogger().info(f\"[ManagedProcess]run...\")\n        returncode = ManagedProcess.run(js7Step, cmd)      \n\n        js7Step.getLogger().info(f\"[ManagedProcess]returncode={returncode}\")\n        js7Step.getOutcome().setReturnCode(returncode)\n        js7Step.getOutcome().putVariable(\"outcome_var_name\", \"outcome_var_value\")\n\n    # Uses the onProcessOrderCanceled() hook after the order has been canceled\n    def onProcessOrderCanceled(self, js7Step):\n        js7Step.getLogger().info(\"Order was canceled\")\n        ManagedProcess.cancel(js7Step)"
      },
      "skipIfNoAdmissionForOrderDay": false,
      "killAtEndOfAdmissionPeriod": false,
      "parallelism": 1,
      "graceTimeout": 1,
      "failOnErrWritten": false,
      "warnOnErrWritten": false,
      "title": "Example of a cancellable subprocess with live output logging.",
      "isNotRestartable": false
    }
  }
}