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.
Prepare the samples
Section titled “Prepare the samples”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.
Write the configuration file
Section titled “Write the configuration file”Create tutorial.conf with the following content.
name: tutorialoption: http_broker: start: true port: 8000plugins: 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: inc1containers: - type_name: example_container name: counter0 processes: - type_name: example_container_increment name: increment0 - type_name: example_container_get name: get0name: tutorialoption: http_broker: start: true port: 8000plugins: process_factories: increment_process_python: language: python path: "./process" container_factories: example_container_python: language: python path: "./container" processes: example_container_python_increment: path: "./container" example_container_python_get: path: "./container"processes: - type_name: increment_process_python name: inc0 - type_name: increment_process_python name: inc1containers: - type_name: example_container_python name: counter0 processes: - type_name: example_container_python_increment name: increment0 - type_name: example_container_python_get name: get0name: tutorialoption: http_broker: start: true port: 8000plugins: process_factories: increment_process_cpp: language: "c++" path: "./build/plugins" container_factories: example_container_cpp: language: "c++" path: "./build/plugins" processes: example_container_cpp_increment: path: "./build/plugins" example_container_cpp_get: path: "./build/plugins"processes: - type_name: increment_process_cpp name: inc0 - type_name: increment_process_cpp name: inc1containers: - type_name: example_container_cpp name: counter0 processes: - type_name: example_container_cpp_increment name: increment0 - type_name: example_container_cpp_get name: get0Configuration files are written in YAML. Let’s go through it from the top.
name and option
Section titled “name and option”name: tutorialoption: http_broker: start: true port: 8000name 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: loading
Section titled “plugins: loading”plugins says which files to load types from. It corresponds to --process in chapter 1 and --container / --container_process in chapter 2.
process_factorieslists Process types.container_factorieslists Container types, andprocessesunder 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.
For the type name increment_process_python, juiz loads increment_process_python.py from ./process.
Always write language: python. ContainerProcesses use the same language as their parent Container.
For the type name increment_process_cpp, juiz loads libincrement_process_cpp.so (.dylib on macOS) from ./build/plugins.
Always write language: "c++" (note that this differs from -l cpp on the command line). ContainerProcesses use the same language as their parent Container.
Writing something in plugins does not run anything yet. juiz just learns the types (how to make them).
processes and containers: creating
Section titled “processes and containers: creating”processes and containers say which instances to create from the loaded types. They correspond to -1 in chapters 1 and 2.
type_nameis a type name listed inplugins, andnameis the name of the instance to create.processescreates two instances,inc0andinc1, from the same typeincrement_process.containerscreates the Containercounter0, and theprocessesunder it create the ContainerProcessesincrement0andget0bound tocounter0.
Instances created with -1 were always named “type name + 0”, but in a configuration file you can choose any name.
Run it
Section titled “Run it”Pass the configuration file with -f. The command is the same for every language.
juiz -f tutorial.conf -dFor Python, run it in a terminal where the venv from chapter 1 is activated.
Call it from outside
Section titled “Call it from outside”Leave juiz running, open another terminal, and list the Processes.
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"]juiz process list# => ["http://127.0.0.1:8000/process/inc0::increment_process_python", "http://127.0.0.1:8000/process/inc1::increment_process_python"]juiz container-process list# => ["core://core/container_process/increment0::example_container_python_increment:counter0", "core://core/container_process/get0::example_container_python_get:counter0"]juiz process list# => ["http://127.0.0.1:8000/process/inc0::increment_process_cpp", "http://127.0.0.1:8000/process/inc1::increment_process_cpp"]juiz container-process list# => ["core://core/container_process/increment0::example_container_cpp_increment:counter0", "core://core/container_process/get0::example_container_cpp_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.
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: []))juiz process call "http://127.0.0.1:8000/process/inc0::increment_process_python" '{"arg1": 3}' -p# => CapsulePtr((value:Value(4), option: []))juiz process call "http://127.0.0.1:8000/process/inc1::increment_process_python" '{"arg1": 10}' -p# => CapsulePtr((value:Value(11), option: []))juiz container-process call "http://127.0.0.1:8000/container_process/increment0::example_container_python_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_python_get:counter0" '{}' -p# => CapsulePtr((value:Value(5), option: []))juiz process call "http://127.0.0.1:8000/process/inc0::increment_process_cpp" '{"arg1": 3}' -p# => CapsulePtr((value:Value(4), option: []))juiz process call "http://127.0.0.1:8000/process/inc1::increment_process_cpp" '{"arg1": 10}' -p# => CapsulePtr((value:Value(11), option: []))juiz container-process call "http://127.0.0.1:8000/container_process/increment0::example_container_cpp_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_cpp_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.
Pass an initial value to a Container
Section titled “Pass an initial value to a Container”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.
containers: - type_name: example_container_python name: counter0 initial_value: 3 processes:3 is passed to the initial_value parameter of the example_container_python function.
containers: - type_name: example_container_cpp name: counter0 value: 3 processes:create_container takes 3 out of the CapsuleMap it receives with args.get_int("value").
This is also why example_container.conf in chapter 2 said value: 10.
Stop juiz with Ctrl+C, start it again, and call get. It returns 3.
juiz container-process call "http://127.0.0.1:8000/container_process/get0::example_container_get:counter0" '{}' -p# => CapsulePtr((value:Value(3), option: []))juiz container-process call "http://127.0.0.1:8000/container_process/get0::example_container_python_get:counter0" '{}' -p# => CapsulePtr((value:Value(3), option: []))juiz container-process call "http://127.0.0.1:8000/container_process/get0::example_container_cpp_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: inc1containers: - 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: get0processes: - type_name: increment_process_python name: inc0 p_apply: arg1: 10 - type_name: increment_process_python name: inc1containers: - type_name: example_container_python name: counter0 initial_value: 3 processes: - type_name: example_container_python_increment name: increment0 p_apply: arg1: 5 - type_name: example_container_python_get name: get0processes: - type_name: increment_process_cpp name: inc0 p_apply: arg1: 10 - type_name: increment_process_cpp name: inc1containers: - type_name: example_container_cpp name: counter0 value: 3 processes: - type_name: example_container_cpp_increment name: increment0 p_apply: arg1: 5 - type_name: example_container_cpp_get name: get0A 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.
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 '{}'# => 11curl -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 '{}'# => 8curl -X PATCH "http://127.0.0.1:8000/api/process/execute?identifier=core://core/process/inc0::increment_process_python" \ -H "Content-Type: application/json" -d '{}'# => 11curl -X PATCH "http://127.0.0.1:8000/api/container_process/execute?identifier=core://core/container_process/increment0::example_container_python_increment:counter0" \ -H "Content-Type: application/json" -d '{}'# => 8curl -X PATCH "http://127.0.0.1:8000/api/process/execute?identifier=core://core/process/inc0::increment_process_cpp" \ -H "Content-Type: application/json" -d '{}'# => 11curl -X PATCH "http://127.0.0.1:8000/api/container_process/execute?identifier=core://core/container_process/increment0::example_container_cpp_increment:counter0" \ -H "Content-Type: application/json" -d '{}'# => 8inc0 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.
Try it yourself
Section titled “Try it yourself”- Remove
processesandcontainers, keep onlyplugins, startjuizand runjuiz process list. It returns an empty list[]. Loading alone does not create any instances. - Add another Container (for example
counter1) tocontainers, with its ownincrement/get.counter0andcounter1hold separate values. The Container name is part of a ContainerProcess ID, so names likeincrement0can be the same under each Container. - Add
decrement_processfrom the example repository topluginsandprocesses, and run the Process that subtracts 1 alongside the others.
Summary
Section titled “Summary”- A configuration file separates
plugins, which loads types, fromprocesses/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_applygives 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.