Skip to content

3. Starting everything from a configuration file

In chapter 1 you started a Process, and in chapter 2 a Container, each on its own. A real robot runs many parts at once: cameras, motors, and the Processes that handle their data. In this chapter you write the Process and Container so far into one configuration file and start them together.

Keep using the example repository you cloned and built in chapter 1. If you have not done that yet, follow Prepare the samples in chapter 1.

In this chapter you create a new configuration file named tutorial.conf at the root of the example repository.

Create tutorial.conf with the following content.

tutorial.conf
name: tutorial
option:
http_broker:
start: true
port: 8000
plugins:
process_factories:
increment_process:
path: "./target/debug"
container_factories:
example_container:
path: "./target/debug"
processes:
example_container_increment:
path: "./target/debug"
example_container_get:
path: "./target/debug"
processes:
- type_name: increment_process
name: inc0
- type_name: increment_process
name: inc1
containers:
- type_name: example_container
name: counter0
processes:
- type_name: example_container_increment
name: increment0
- type_name: example_container_get
name: get0

Configuration files are written in YAML. Let’s go through it from the top.

name: tutorial
option:
http_broker:
start: true
port: 8000

name is the name of this system. http_broker under option configures the HTTP broker you have been starting with -d. port changes the port it listens on.

plugins says which files to load types from. It corresponds to --process in chapter 1 and --container / --container_process in chapter 2.

  • process_factories lists Process types.
  • container_factories lists Container types, and processes under each one lists the ContainerProcess types bound to that Container.

The keys are type names. juiz looks in the directory given by path for the file that matches the type name.

For the type name increment_process, juiz loads libincrement_process.so (.dylib on macOS) from ./target/debug. If language is omitted, it is treated as rust.

Writing something in plugins does not run anything yet. juiz just learns the types (how to make them).

processes and containers say which instances to create from the loaded types. They correspond to -1 in chapters 1 and 2.

  • type_name is a type name listed in plugins, and name is the name of the instance to create.
  • processes creates two instances, inc0 and inc1, from the same type increment_process.
  • containers creates the Container counter0, and the processes under it create the ContainerProcesses increment0 and get0 bound to counter0.

Instances created with -1 were always named “type name + 0”, but in a configuration file you can choose any name.

Pass the configuration file with -f. The command is the same for every language.

Terminal window
juiz -f tutorial.conf -d

For Python, run it in a terminal where the venv from chapter 1 is activated.

Leave juiz running, open another terminal, and list the Processes.

Terminal window
juiz process list
# => ["http://127.0.0.1:8000/process/inc0::increment_process", "http://127.0.0.1:8000/process/inc1::increment_process"]
juiz container-process list
# => ["core://core/container_process/increment0::example_container_increment:counter0", "core://core/container_process/get0::example_container_get:counter0"]

The order may change from run to run. There are two instances of the same type increment_process, inc0 and inc1, whose IDs differ only in the instance name part. Call each of them.

Terminal window
juiz process call "http://127.0.0.1:8000/process/inc0::increment_process" '{"arg1": 3}' -p
# => CapsulePtr((value:Value(4), option: []))
juiz process call "http://127.0.0.1:8000/process/inc1::increment_process" '{"arg1": 10}' -p
# => CapsulePtr((value:Value(11), option: []))
juiz container-process call "http://127.0.0.1:8000/container_process/increment0::example_container_increment:counter0" '{"arg1": 5}' -p
# => CapsulePtr((value:Value(5), option: []))
juiz container-process call "http://127.0.0.1:8000/container_process/get0::example_container_get:counter0" '{}' -p
# => CapsulePtr((value:Value(5), option: []))

The Process from chapter 1 and the Container from chapter 2 now run together inside one juiz. inc0 and inc1 are separate instances created from the same type, but a Process has no state, so either one returns the same result for the same arguments.

Besides type_name and name, a containers entry can also hold values passed to the function that creates the Container. Add one line to the counter0 entry so the counter starts at 3.

containers:
- type_name: example_container
name: counter0
initial_value: 3
processes:

3 is passed to the initial_value parameter of the example_container function.

Stop juiz with Ctrl+C, start it again, and call get. It returns 3.

Terminal window
juiz container-process call "http://127.0.0.1:8000/container_process/get0::example_container_get:counter0" '{}' -p
# => CapsulePtr((value:Value(3), option: []))

You changed the starting point of the behavior with the configuration file alone, without touching the code.

Give a Process’s arguments initial values: p_apply

Section titled “Give a Process’s arguments initial values: p_apply”

Not only Containers: you can also give values to a Process’s arguments in the configuration file. Write p_apply in a processes entry, or in a processes entry inside containers, and list argument names and values under it.

Set arg1 of inc0 to 10 and arg1 of increment0 to 5.

processes:
- type_name: increment_process
name: inc0
p_apply:
arg1: 10
- type_name: increment_process
name: inc1
containers:
- type_name: example_container
name: counter0
initial_value: 3
processes:
- type_name: example_container_increment
name: increment0
p_apply:
arg1: 5
- type_name: example_container_get
name: get0

A p_apply value goes into the argument right after the instance is created and becomes its initial value. The value is used when the Process is executed without arguments. The Execution Context you use in the next chapter runs Processes this way. The call you have used so far passes all arguments every time, so p_apply values are not used there.

Restart juiz and execute them without arguments through execute in the HTTP API.

Terminal window
curl -X PATCH "http://127.0.0.1:8000/api/process/execute?identifier=core://core/process/inc0::increment_process" \
-H "Content-Type: application/json" -d '{}'
# => 11
curl -X PATCH "http://127.0.0.1:8000/api/container_process/execute?identifier=core://core/container_process/increment0::example_container_increment:counter0" \
-H "Content-Type: application/json" -d '{}'
# => 8

inc0 adds 1 to the 10 in arg1 and returns 11. If you execute inc1, which has no p_apply, the same way, the argument’s default value 0 is used and it returns 1. increment0 adds 5 to the counter that started at 3 and returns 8.

If p_apply names an argument the Process does not have, juiz stops with an error at startup. For example, if you mistype arg1 as arg10, you get an error like this:

Error:setup_objects() failed in setup in system.rs
Caused by:
0: setup_processes(...) in setup_objects() in setup_objects.rs
1: p_apply(arg_name='arg10', value=10)
2: Can not find Process::Inlet(arg10)

You notice the typo when juiz starts, not later while it is running.

  • Remove processes and containers, keep only plugins, start juiz and run juiz process list. It returns an empty list []. Loading alone does not create any instances.
  • Add another Container (for example counter1) to containers, with its own increment / get. counter0 and counter1 hold separate values. The Container name is part of a ContainerProcess ID, so names like increment0 can be the same under each Container.
  • Add decrement_process from the example repository to plugins and processes, and run the Process that subtracts 1 alongside the others.
  • A configuration file separates plugins, which loads types, from processes / containers, which create instances from them.
  • One type can produce several instances with different names. The instance name becomes part of the ID.
  • Per-instance settings, such as a Container’s initial value, can also be passed in the configuration file.
  • p_apply gives initial values to a Process’s arguments. They are used when the Process is executed without arguments, for example from an Execution Context.
  • The configuration file entries are summarized in the Configuration file guide.

In the next chapter you add connections between Processes, and when to run them, to the configuration file. Move on to Connecting Processes: connect and Execution Context.