Skip to content

Program

The Program block lets you integrate any program or script into your workflow, provided that it supports command-line execution and file-based input and output (batch mode). The block automates program launches and handles file transfers between your storage in pSeven Enterprise, the program, and other blocks in the workflow. It's often used with Text blocks set up to generate input files for the integrated program and parse its output files.

Getting started

The Program block is commonly used to run Windows software installed on an extension node - a workstation or server connected to pSeven Enterprise over the network. To set up the block, you'll need:

  • The network name of the computer where your software is installed. This computer will be the run host for both the block and the software.
  • The command that launches your software, tested and verified to work from the default system command prompt on the run host.
  • Access to the run host and a user account there, so you can test commands locally and gather troubleshooting information if errors occur.

There are three main setup scenarios with this block:

  • Many programs accept paths to input and output files as command line arguments. If this is your case, you can use special command line syntax with port names in place of paths. See General program launch.
  • If you are running engineering software that works with a project folder and requires a certain project location and structure, see Running engineering software.
  • If you are already using batch scripts to run your programs, see Running scripts.
Linux software

The block can run Linux software, but this software must be installed on every node of the Kubernetes cluster where pSeven Enterprise is deployed. Ask your admin whether this is possible in your deployment.

By default, there is no software on the cluster nodes except system packages and Python provided by pSeven Enterprise. Technically you can run Python scripts with the Program block - however, in most cases the Python script block is more practical for this.

General program launch

This section provides a basic setup example for a program that accepts paths to its working files and folders as command line arguments or options. A basic example of such a command line is:

thetool -i "D:\Work\input.dat" -o "D:\Work\result.dat"

where thetool is the name of the program executable, -i and -o are options that specify the input and output paths. Depending on how your software is installed, running it might require a full path, such as "C:\Programs\The Tool\thetool.exe" instead of just thetool.

Given this example command, general steps to set up the block are:

  1. Test running the software locally on the run host, using normal input files. Make sure your commands complete without errors and produce expected results.
  2. Select a Program block in your workflow to view its settings in the Block properties pane. Program blocks are entirely configured in this pane; opening the block just displays its configuration overview.
  3. At the top of the Block properties pane, under "Run on:", select the run host.
  4. Add an input file to the block configuration:

    1. Click next to the Inputs header in Block properties and choose Input file from the drop-down menu.
    2. In the Add an input file dialog, enter the alias you want to use for this file - for instance, settings file. This is not the file name; it's how you reference this file in your configuration, in particular the command on the Run input port.
    3. Click OK in the dialog. A new input port Input files.settings file appears in Inputs. You'll pass program input files to this port.
  5. Add a result file: click in Inputs, choose Result file, enter its alias: output file. These ports appear:

    • Input: Result files.output file. Sets where to save this file in the workflow results (in the workflow run directory).
    • Input: Result files.output file.Take from. Leave unset because you'll reference the file as ${output file} in the command. This setting is used for programs that don't accept output file paths as arguments.
    • Output: Result files.output file. Outputs the file so you can send it to other blocks.
  6. On the Run input port, enter the same command you've used locally, replacing file paths with ${...} aliases:

    thetool -i "${settings file}" -o "${output file}"
    

    For files and folders, always quote the ${...} aliases in the command. The paths they resolve to can contain spaces, and an unquoted path with spaces would be split into separate arguments by the command interpreter.

  7. Set the Input files.settings file port:

    • select an existing file from your storage, or
    • link this port to an output of another block - for instance, the Output file port of a Text block that generates input files.
  8. Link the Result files.output file output port to a downstream block that processes the program output - for instance, to the Input file port of another Text block that parses output files.

  9. If you want to save a copy of the output file in workflow run results, set the save location on the Result files.output file input port. Choose a location inside the workflow run directory - the block cannot write any files outside it.

    Allowed save locations for output files

    Blocks cannot write files outside the current workflow run directory. It is recommended that you keep the default file location in the file dialog ("Block working directory") and only change the path. Another allowed location is "Workflow or run" with a relative path - with such settings, the block will save the file to the run directory root.

When the block runs, it creates a temporary remote working folder on the run host, copies all input files there, and launches your program with that folder as the current working directory. Once the program exits, the block collects result files and copies them to the current workflow run directory, then outputs their storage paths to ports.

This is a basic example; for full details about program launch on the run host and related settings, see How it runs.

Running engineering software

This section provides a basic setup example for engineering software that works with a project folder. The scenario has a typical pattern: you maintain a project template, update one or more files before each run, and collect specific result files afterwards. Engineering software often doesn't support command line arguments for input and output files, or requires all paths relative to the project folder - so you can't use ${file} aliases as in the general program scenario. Instead, you'll use ports that set input and output file locations as relative paths in the project folder.

To start, you'll need the basic setup information and a project to use as a template. That project must be portable (self-contained): it cannot reference files outside the project folder, and cannot use absolute file paths in any of its settings. Think of it as a project you could copy to another workstation and run there without changes. This is a prerequisite: if your project has hardcoded absolute paths or external dependencies, make it portable first.

A generic example of the project launch command is:

"C:\Programs\ACME\solver.exe" -B -F model.apj -R user_files\journal.ajn

For example purposes, assume that:

  • model.apj is the main project file,
  • user_files\journal.ajn is a journal script that configures the solver run,
  • the workflow contains a Text block, which generates a new journal.ajn for each run, updating it with new parameter values from workflow inputs,
  • the solver writes evaluated designs to CSV files in the project folder.

Given this example, general steps to set up the block are:

  1. Select a Program block in your workflow to view its settings in the Block properties pane. Program blocks are entirely configured in this pane; opening the block just displays its configuration overview.
  2. At the top of the Block properties pane, under "Run on:", select the run host.
  3. Upload your project template to the workflow folder or another location in your pSeven Enterprise storage.
  4. On the Remote working folder.Prototype input port, select the uploaded folder. The block will copy its contents into the remote working folder before running your software. This will be the starting state of your project on the block's run host.
  5. If your template project is large and only a subset of files needs to travel to the run host, set Remote working folder.Prototype mask to filter by extension or name. For example, set *.a?? on this port to copy only the main project files with .apj and .ajn extensions.

    If you need multiple masks, open the Edit value dialog on this port and switch the type at the top left to List of masks. Add as many masks to the list as you need.

    Example masks
    • *.dat - all files with the .dat extension in the folder root; doesn't match files in subfolders
    • **\*.dat - same, but also matches .dat files in all subfolders
    • user-?? - folders named user-01, user-02, and so on
    • params-??.* - files with any extension named params-01, params-02, and so on
  6. Add the journal file as an input file to the block configuration:

    1. Click next to the Inputs header in Block properties and choose Input file from the drop-down menu.
    2. In the Add an input file dialog, enter the alias you want to use for this file - for instance, working journal. This is not the file name; it's how you reference this file in your configuration. In particular, this alias is used in port names.
    3. Click OK in the dialog. A new input port Input files.working journal appears in Inputs. You'll pass the journal file with new parameter values to this port.
    4. Link the Output file port of the Text block to the Input files.working journal input.
    5. On the Input files.working journal.Save as port, set a path relative to the project folder where the input file should land: user_files\journal.ajn. You don't need to remove journal.ajn from your project template: the block will first copy the template to the run host, then write your input files and folders on top of it.

      By default, files generated by other blocks are temporary and have random names. You have to set both the path (the user_files\ subfolder) and the filename, or the file will end up at a path like user_files\~2fed64ca74acefc3. (1)

      1. ~ as the first character is the temporary file naming convention in pSeven Enterprise.
  7. On the Run port, write the launch command.

    "C:\Programs\ACME\solver.exe" -B -F model.apj -R user_files\journal.ajn
    

    Since the remote working folder contains the full project and is the current working directory when the solver runs, you can use exactly the same command as for a normal launch.

  8. To save the solver results to your workflow run directory:

    1. set the Results.Mask input port to *.csv
    2. on the Results.Store to port, select where to save the files

    If your solver produces result files with several different extensions - for example, .csv and .dat - open the Edit value dialog on the Results.Mask port and switch the type at the top left to List of masks. Add as many masks to the list as you need.

  9. To send solver results to another block:

    1. Add a result folder: click in the Inputs pane, choose Result folder, enter its alias: designs.
    2. Set the Result folders.designs.Take from input port to . (a dot). This tells the block to collect results from the remote working folder root - that is, from the working project folder.
    3. Set Result folders.designs.Mask to *.csv to collect only CSV files.
    4. Link the Result folders.designs output port to the block that post-processes the results.

    If you want to also save a copy of this output folder in workflow results, set the save location on the Result folders.designs input port. Choose a location inside the workflow run directory - the block cannot write any files outside it.

    Allowed save locations for output files

    Blocks cannot write files outside the current workflow run directory. It is recommended that you keep the default file location in the file dialog ("Block working directory") and only change the path. Another allowed location is "Workflow or run" with a relative path - with such settings, the block will save the file to the run directory root.

Verify paths before the first real run

To check that paths in file and folder settings are correct, you can replace your actual Run command with echo and ${...} aliases.

echo %cd% - "${Remote working folder}" - "${working journal}"

The block resolves all ${...} aliases to absolute paths on the run host, which are determined by your settings for Remote working folder.Path, Remote working folder.Create subfolder, and file locations. The workflow run log will show the actual paths the block resolved.

%cd% is a Windows system variable that contains the current working directory path. Note that %cd% and ${Remote working folder} resolve to the same path.

When the block runs, it creates a temporary remote working folder on the run host, copies all contents of your project template there, and launches your software with that folder as the working project. Once the software exits, the block collects result files, copies them to the workflow run directory, and outputs to ports - according to your settings.

This is a basic example; for full details about software launch on the run host and related settings, see How it runs.

Running scripts

If you have a script (.bat file) you normally use to launch your software, you can run this script in the Program block with minor modifications.

  1. Select a Program block in your workflow to view its settings in the Block properties pane. Program blocks are entirely configured in this pane; opening the block just displays its configuration overview.
  2. At the top of the Block properties pane, under "Run on:", select the run host.
  3. Add input files and folders, result files to the block configuration. Set their aliases in the add dialogs - for example, settings file, project, journal.
  4. In your script, replace file paths with ${...} aliases.

    @echo off
    "C:\Programs\ACME\preprocessor.exe" -prepare "${settings file}"
    "C:\Programs\ACME\solver.exe" -B -F "${project}\model.apj" -R "${journal}"
    
  5. Open the Edit value dialog on the Run port and switch the type at the top left to Script. Paste your script there.

When the block runs, it creates a temporary remote working folder on the run host and copies all input files there. Then it resolves all ${...} aliases in the script, writes it to a temporary file, and passes that file to the system interpreter. The remote working folder becomes the current working directory for the script. Once the script exits, the block collects result files and copies them to the current workflow run directory, then outputs their storage paths to ports.

This is a basic example; for full details about program launch on the run host and related settings, see How it runs.

How it runs

The sections above provide basic examples, assuming that most settings - in particular, logging and error handling - are left at their defaults. In most cases, your tasks will require certain adjustments to that basic configuration, depending on the features of the software you're integrating, the desired file layout, workflow behavior, and so on.

Knowing how the block launches programs on the run host helps you adjust the block for your specific scenario.

During a workflow run, pSeven Enterprise sends the block to the run host you've selected and starts it there. Here's the breakdown of what happens next.

  1. The block creates a remote working folder on the run host. This is either a temporary folder or the folder specified in Remote working folder.Path, with an optional subfolder.

    • If Remote working folder.Create subfolder is enabled, the block creates a unique subfolder inside the remote working folder for each run. The resulting path is:

      {Remote working folder.Path or temporary folder}\{random subfolder if Remote working folder.Create subfolder is True}\
      

      This ensures that parallel runs of the same block - for example, runs inside a loop or in batch mode - do not interfere with each other's files.

    • You can use echo %cd% or echo ${Remote working folder} as the Run command to check the resulting working folder path on the run host.

  2. The block copies all contents of the folder specified by Remote working folder.Prototype to the run host, placing them at the remote working folder root.

  3. The block copies the input files and folders to the remote working folder.

    • Locations are determined by your settings on the Input files.{file}.Save to, Input files.{file}.Save as, Input folders.{folder}.Save to, Input folders.{folder}.Save as ports. If a file or folder location is not specified, it lands at the remote working folder root by default.
    • Input files overwrite existing files copied with the remote working folder prototype, if they have the same names and paths.
    • Input folders are merged with the prototype folders, if they land at the same path.

    The path to a file or folder is generally:

    {Remote working folder}\{"Save to" setting}\{"Save as" setting or original filename}
    
  4. The block resolves ${...} aliases in the Run command.

    • File and folder aliases are replaced with absolute paths to their copies on the run host (inside the remote working folder).
    • Substitution and environment variable aliases resolve to their port values.
  5. The block sets environment variables if you've added them to the block configuration.

    The variables are set for your program or script only - so the environment settings are temporary. The block never changes variables in the system environment.

  6. The block sets the remote working folder as the current working directory and executes your Run command or script there.

  7. While the command runs, its console output is captured by the block and shown in the Run log pane.

    See Logging for other logging features available in this block.

  8. Once the command exits, the block checks its exit code and collects the configured result files and folders.

    • If the command exits successfully, the block looks for result files at the locations resolved by the corresponding ${file} aliases or determined by your file location settings (Result files.{file}.Take from, Result folders.{folder}.Take from).
    • If a required result file is not found at its expected location, the block treats this as a command error.
  9. The block copies the collected result files and folders from the run host to the current workflow run directory.

    • These copies are temporary by default. They are stored in the run directory only while other blocks use them during the workflow run.
    • The storage paths of the copied files are sent to the corresponding output ports.
    • If you configure a save path for the result, the file is also saved there as part of the workflow run results.
  10. If the command has completed successfully and all required result files have been found, the block outputs the corresponding result ports and signals completion through the @go output port.

    The block also outputs the program's exit code through the Exit code output port.

  11. If the program exits with an error code (not in Success codes), or a required result file is not found at its expected location, or an error message was detected in logs, the block stops with an error by default and doesn't output anything.

    You can set up error handling to change this behavior.

  12. After the command has finished and the block has collected its results, the remote working folder is cleaned up according to your Remote working folder.Cleanup setting.

    By default, the cleanup removes all copies of input and result files on the run host.

    If you need to inspect files on the run host for troubleshooting, switch Remote working folder.Cleanup to "Disabled".

Input files

When the Program block runs, it creates copies of all input files on its run host before the program launch. By default, every such copy lands directly in the remote working folder (at its root) under the same name as the original file. If a file with that name already exists in the remote working folder, there are two cases:

  1. The existing file comes from the remote working folder prototype. The input file overwrites it; this behavior is intended to support running engineering software.
  2. The existing file is another input file. The block stops with an error: input files cannot overwrite each other - they can only overwrite the prototype's files.

If your program accepts file paths as command line arguments, add ${...} aliases to the command on the Run port. The block replaces the aliases with absolute paths to working copies of input files on the run host.

thetool -i "${input file}" -o "${output file}"

If your program needs files at fixed locations - with specific filenames or in certain subfolders in its working directory - configure where each file should land using these input ports:

  • Input files.{file}.Save to - path to the subfolder where the file should be placed, relative to the working folder or project folder. The file keeps its original name, unless you also set Input files.{file}.Save as.
  • Input files.{file}.Save as - the name under which the file is saved.

As a shortcut, you can also set both the path and the filename on the Input files.{file}.Save as port (subfolder\path\filename.ext), and leave Input files.{file}.Save to unset.

For files received from other blocks, the name setting (Input files.{file}.Save as) is often required. Such files have random names by default; see the examples below for details.

Place an input file from storage in a required subfolder

Assume a program reads its input from INPUTS\input.dat in the folder where it runs, with no command line option to specify the path.

  1. Upload input.dat to the workflow folder or another place in your storage.
  2. Add an input file in block settings. Give it an alias - datfile, for example.
  3. On the Input files.datfile port, select the file from your storage.
  4. Set the Input files.datfile.Save to port to INPUTS.

Before running the program, the block will place the file at INPUTS\input.dat inside the program's working folder.

You don't need to specify Input files.datfile.Save as, unless you want to rename the file in the working folder. For example, you might store it as input_template.dat but set Input files.datfile.Save as to INPUTS\input.dat, so the file ends up at INPUTS\input.dat as expected by the program.

Alternatively, you can set INPUTS on Input files.datfile.Save to and input.dat on Input files.datfile.Save as, if you need these settings as separate ports.

Place an input file from port in a required subfolder

Assume there's a CSV input file generated by another block, which you need to place at model_files\user\designs.csv inside the working project.

  1. Add an input file in block settings. Give it an alias - design file, for example.
  2. Link the other block's output to the Input files.design file input.
  3. Set the Input files.design file.Save as port to model_files\user\designs.csv.

By default, files generated by other blocks are temporary and have random names. You have to set both the path and the filename, or the file will end up at a path like model_files\user\~2fed64ca74acefc3. (1)

  1. ~ as the first character is the temporary file naming convention in pSeven Enterprise.

Alternatively, you can set model_files\user on Input files.design file.Save to and designs.csv on Input files.design file.Save as, if you need these settings as separate ports.

Result files

After your program runs, the block collects result files from the remote working folder and copies them to the workflow run directory (in your storage), where other blocks can get them. Storage paths of these copies are sent to the block's output ports. Copies in the storage are temporary by default: they are deleted automatically, except the files you choose to retain by setting their storage location on the Result files.{file alias} input port.

To find a program result file, the block requires you either to include the file's ${...} alias in your commands or to set the Result files.{file alias}.Take from input port.

  • If you use the ${...} alias, the block assigns the file a location automatically: it generates a path, which you have to pass to the program as a command line argument.
  • If your program doesn't accept paths as command line arguments and writes output files at fixed locations, set their paths on the Result files.{file alias}.Take from input ports. These paths are relative to the remote working folder. After your program finishes, the block looks for result files at these paths.
  • You can use both: if Result files.{file alias}.Take from is set, the ${...} alias of that file resolves to an absolute path determined by the port setting.
  • If you use neither, the block stops with an error before running your program.

If, after the program exits, any output file isn't found at its expected path, the block treats this as a program error, which it handles according to your Command error port setting.

To save an output file, set its save location on the Result files.{file alias} input port. It can be:

  • a storage path relative to the block working directory in the current run directory (select "Block working directory" in the file dialog), or
  • a path relative to the root of the current run directory (select "Workflow or run" in the file dialog).

Note that the block cannot write output files outside the current run directory. That is, writing to the workflow folder and other folders is prohibited for all blocks.

Result files.{file alias} output ports send file paths regardless of the save location setting. For files with the Result files.{file alias} input unset, the output paths point to temporary file copies in the current workflow run directory. Those copies have random names without extension by default, like ~2fed64ca74acefc3. If you want to send a file to another block, which requires certain extensions for input files, there are two options:

  1. Set a save location for the file on its Result files.{file alias} input port. Use any name and the required extension.
  2. If you want the file to be temporary, set the filename on Result files.{file alias} to ~.{extension} - for instance, ~.prt. With this setting, the block will output a temporary file with a random name and your extension, like ~2fed64ca74acefc3.prt.

~ as the first character is the temporary file naming convention in pSeven Enterprise. If there's a filename that starts with ~ in your settings, the block will generate a random name for that file.

Input and output folders

Folders are generally set up the same way as files.

  • Input folders are copied to the remote working folder before running the program.
  • By default, an input folder lands at the remote working folder root under its original name.
  • Input folders.{folder alias}.Save to and Input folders.{folder alias}.Save as settings control folder placement the same way as for input files.
  • If a folder with the same name already exists on the run host, and that folder is part of the remote working folder prototype, then the input folder merges with the existing one, and files from the input folder overwrite existing ones.
  • If such a folder exists but it is another input folder (not part of the prototype), it causes an error: input folders cannot merge with each other - they can only merge with the prototype's folders.
  • Result folders are collected from the run host after the program finishes.
  • To make the block find and collect result folders, you have to include their ${...} aliases in your command or script or set their paths on the Result folders.{folder alias}.Take from ports.

Folders support an additional file copy mask setting:

  • Input folders.{folder alias}.Mask - if set, only the files that match this mask are actually copied to the remote working folder.
  • Result folders.{folder alias}.Mask - if set, only the files that match this mask are included when the block saves the result folder or sends it to an output port.

Example masks

  • *.dat - all files with the .dat extension in the folder root; doesn't match files in subfolders
  • **\*.dat - same, but also matches .dat files in all subfolders
  • result-?? - folders named result-01, result-02, and so on
  • result-??.* - files with any extension named result-01, result-02, and so on

For simple masks such as *.dat, enter them in the port value field in Block properties. For more complex masks - for example, if you need two or more kinds of files with different extensions - open the Edit value dialog on the mask port and switch the type at the top left to List of masks. Add as many masks as you need; the block will include any file that matches any mask from the list.

Use masks to avoid copying large files

Engineering project folders often contain files that don't need to travel to the run host: cached geometry, binary results from previous runs, mesh databases. Adding an input folder mask limits what the block copies, which can save noticeable time, especially if the Program block runs in a workflow loop.

Program options as ports

Options are additional command line arguments that change program settings. For example, many engineering solvers support an option that sets the number of solver threads - usually -n {number of threads}. The command line might include many options:

thetool.exe -n 4 -a -R -i "D:\Work\Project X\input.dat"

You can expose program options as ports by adding substitutions in block settings.

  1. Click in Inputs, select Substitution, enter its alias - for example, N threads.
  2. The Substitutions.N threads port appears. Set its value to 4.
  3. Add another substitution, enter its alias: Options. Set it to -a -R.
  4. Use the aliases in your command on the Run port:

    thetool.exe -n ${N threads} ${Options} -i "${input file}"
    

The ${N threads} and ${Options} aliases are replaced with port values when the block runs. You can change program settings by editing port values or sending them from other blocks.

Environment variables

Your program might read settings from environment variables - for example, get the path to its license file from the TT_LICENSE_FILE variable. You can set or override that variable on the block's run host:

  1. Click in the Inputs pane, select Environment variable.
  2. In the Add environment variable dialog, enter the exact name of the variable: TT_LICENSE_FILE.
  3. The Environment variables.TT_LICENSE_FILE port appears. Set its value to the license file path on the run host.

The block sets the TT_LICENSE_FILE variable for the program only. It doesn't change the system TT_LICENSE_FILE variable, if it is already set on the run host. The environment variable settings in the block are temporary; they apply only to the program (commands, script) launched by the block.

You can test environment variables in Windows

Setting environment variables via the block is similar to opening a command prompt, setting variables there, and running your program from it:

  1. Open a new command prompt window.
  2. Set the variable you're testing - for instance: set TT_LICENSE_FILE=C:\Licenses\The Tool v123.lic. This sets it only for the current window.
  3. Run your program in the same window. The program inherits the variable you've set.

You can also set variables inline in the Run command, before the program call:

set TT_LICENSE_FILE=C:\Licenses\The Tool v123.lic && thetool.exe ${options substitution} -i "${input file}"

Or, if the program reads settings, input and output paths from environment variables:

set TT_OPTIONS=${options substitution} && set TT_INPUT=${input file} && thetool.exe

Logging

By default, the block captures all messages output by your program - the stdout and stderr streams of your command or script - and relays all captured messages to the workflow run log. You can view it in the Run log pane on a workflow run tab.

To suppress program logs in the workflow run log, set the Logging.Show command log input port to No. With this setting, the block only logs its own errors and warnings - for instance, if it can't find a program output file you've specified.

To save the full log to your run results, set these input ports:

  • Logging.Log file: save location. Default: command.log in the block working directory in the current run.
  • Logging.Save log file: when to save the full log. By default, the block saves it only if your program (command, script) exits with an error.

If your program writes logs to a file rather than the standard output, set Logging.Command log file to the location of that file. Use a file name, path relative to the remote working folder, or an absolute path on the run host. While your program runs, the block reads that file and adds its contents to the run log and to the full log file.

Solver that writes log to a file

Some engineering solvers write all messages to a .log file in the project folder. If you run such a solver without the Logging.Command log file setting, its messages won't appear in the run log, and Logging.Fail pattern won't work, since the block has nothing to monitor.

Set Logging.Command log file to the log file name or path relative to the project folder - for example, solve.log or logs/main.log. The block will read that file continuously while running and relay new messages from the file to the run log and to the full log file.

Handling program errors

If an error occurs in your program or script, the block stops with an error by default and doesn't send anything to its output ports. It also doesn't store any result files to the workflow run directory but will save the full log file according to your logging settings.

To detect errors, the block uses the exit code of your program or script. If the program doesn't set a specific exit code on error, you can set up the block to detect errors in logs.

If you switch the Command error input port to "Best effort", the block suppresses command and program errors: it finishes normally and sends outputs for troubleshooting.

  • The exit code is output to the Exit code port.
  • If you've set up saving a full log, the log file is saved and output to the Log file port.
  • Result file and folder ports output the program results, if those files and folders exist on the run host. If they don't, the ports output Path values pointing to their expected locations in the workflow run directory.

This behavior enables designing workflows that are robust to errors in integrated programs or scripts.

  • If downstream blocks that receive files from Program can handle missing input files, simply select "Best effort" on the Command error port and link file outputs directly to those blocks.
  • Otherwise, use a Condition block to check the exit code sent by Program (the Exit code port). Set up links between Condition and downstream blocks so they get the input files only if the exit code is 0. If you've set a custom list of success codes on the Success codes input, set up Condition to check that the exit code is in that list.

Program errors and block or system errors are different

The Command error setting affects block behavior only in cases when errors occur in the program - for example:

  • the program or script exit code is not in the list of success codes (the Success codes port)
  • the program has timed out
  • an error message is detected in the program logs
  • the program didn't write its expected outputs - the result files you've set up in the block

The block can detect and handle such errors because it controls the program launch and can monitor the program's processes, its outputs, exit codes, and so on.

The block cannot handle system errors - for example, if the host computer runs out of memory, Windows stops the block process, or you stop the workflow run. Also it does not handle errors caused by misconfiguration - for example, if you set the same name for two input files (same Input files.{file 1 or 2}.Save as setting), or attempt overwriting a subfolder from the remote working folder prototype with an input file (files can't overwrite folders, folders can't overwrite files). In such cases, the Command error setting doesn't affect the outcome, which is usually a block error that stops the workflow run.

Using exit codes

To detect program errors, the block uses the program's exit code. It is an integer value that every program sends to the operating system when it finishes, errors, crashes or otherwise terminates its process. In Windows, this is also known as error level or the built-in ERRORLEVEL variable in batch scripts. If the Program block stops a workflow run due to an error in the program, usually there is a line in the run log that shows the exit code.

Commonly encountered error codes are:

  • 1 - general error
  • 2 - user error: wrong option, incorrect syntax
  • 127 - system command not found (in Linux)
  • 9009 - system command not found (in Windows)

Certain exit codes are set by the block

Exit codes 100 and 124 are special. They are set by the block, replacing the program's exit code.

  • 100 - You've set up error detection in logs, and the block has detected an error message but didn't stop the program immediately. This can occur only if you've also set Command error to "Best effort"; see Detecting errors in logs for details.
  • 124 - You've set a time limit, and the program timed out so the block interrupted it.

Programs can define their own exit codes. The general convention is that the only success code is 0, and errors are indicated by codes 1 or greater. However this convention is not enforced by the OS, so certain programs ignore it - for example:

  • Some programs always exit with the code 0, so their errors are not detectable by the exit code. In this case, if the program prints error messages to its log, you can detect errors in logs.
  • Some exit with a non-zero code when they finish with a warning while producing results normally. If this is your case, add such codes to the list on the Success codes input port.

To find the codes your program uses, check its documentation and command line help. If the codes are not documented, test running the program from the command line with wrong options, invalid or missing inputs and so on. After each program launch, type echo %ERRORLEVEL% - it outputs the exit code of the preceding command.

Checking program exit codes in Windows

rem Normal launch assuming the input file exists and is valid, the project folder is writable and so on.
rem Exit code should be 0.
thetool -i "D:\Work\input.dat" -o "D:\Work\result.dat"
echo Exit code: %ERRORLEVEL%

rem A typo in a system command (`dir /o`).
rem Exit code should be 9009 because "&&" stops execution if there's an error in the preceding command.
die /o && thetool.exe
echo Exit code: %ERRORLEVEL%

rem Invalid option -BAD.
rem Exit code should be 1 or greater, commonly 2.
thetool -BAD -i "D:\Work\input.dat" -o "D:\Work\result.dat"
echo Exit code: %ERRORLEVEL%

If the program returns non-zero codes on success, or you want to ignore certain errors, add those codes to the list on the Success codes input port.

Programs that use non-zero codes for warnings

Some programs use exit codes to communicate more than success or failure. For example, a mesh generator might return:

  • 0 - clean run
  • 4 - completed with mesh quality warnings (result is usable)
  • 8 - completed with errors (result may be unusable)

If code 4 is acceptable in your workflow, add it to Success codes, making it (0, 4). Don't remove 0, or the block will treat clean runs as errors.

Detecting errors in logs

Engineering tools often return exit code 0 (success) even on failure - for example, when a convergence criterion isn't met, a license error occurs, or a mesh quality check fails. In such cases, the exit code gives no information, but you can still detect program errors by monitoring its logs.

On the Logging.Fail pattern input port, set one or more strings that only appear in your program's error output.

  1. Run the program normally with a known-bad input, which makes the run fail.
  2. Search the program's output or log file for a consistent error indicator. For example, error messages might start with Error: or contain details such as Convergence not achieved or License checkout failed.
  3. Copy the identifying part of the message to the Logging.Fail pattern input port.

    • If you need to detect many different messages, open the Edit value dialog for the Logging.Fail pattern port and switch the type at the top left to List[String]. Add as many message strings as you need.

While the block runs, it monitors the program's standard output and the log file - if you've set Logging.Command log file. If any message there contains any of the strings you've added on Logging.Fail pattern, the block treats this as a program error:

  • With Command error set to "Block error" (default), the block stops immediately.
  • With Command error set to "Best effort", the block continues and doesn't interrupt the program if it still runs.

    Exit code 100 is a special code set by the block, which you can use to reliably identify the cases when program errors are only detectable in logs.

    Once the program finishes, the block checks its exit code:

    • If the program has set an exit code that is not in Success codes, the block outputs it to the Exit code port.
    • If the program exit code is a success one (0 or other from Success codes) in spite of errors in the log, the block sends 100 to the Exit code port.

Regular expressions as error patterns

If you're familiar with regular expressions, you can also use them to detect errors. In the Edit value dialog for Logging.Fail pattern, switch the type to RegEx or List[RegEx], and input your expressions.

Setting a run time limit

On certain errors, a program might stop responding but not exit - causing the block to wait indefinitely. To prevent this, set a run time limit with the Timeout input port. When this limit is reached, the block interrupts the program, sets exit code to 124, and handles the error according to your Command error setting.

Accepted formats:

  • 1d 2h 34m 56s - days, hours, minutes, seconds. Any combination works: 1d 12h, 5h, 30m, and so on. Spaces are optional.
  • 27:34:56 - hours:minutes:seconds. Hours can exceed 24.
  • 95696 - seconds.