Skip to main content

Write Node Code

Nodes contain code that processes data. This guide shows you how to write node code in Rust, Python, or C++ to implement your node’s logic.

Prerequisites

Before you begin, make sure you have:

Node Created

A node created in your graph with input and output ports configured.

Schemas Defined

Schemas created for the data types your node will use.

Language Knowledge

Basic familiarity with Rust, Python, or C++ (depending on your node’s language).

Graph Editor Open

Cerulion Graph Editor running with your graph open.
You can write node code in Rust, Python, or C++. Each language has its own syntax, but the concepts are the same.

What You’ll Do

You’ll write code that:
  • Receives data from input ports
  • Processes the data (your business logic)
  • Sends results through output ports

Step-by-Step Guide

1

Select the node

Click on the node you want to write code for.
The node should be selected, and the properties panel should show the node’s properties.
2

Open code editor

In the properties panel, click the Code button (or double-click the node).
The code editor should open, showing a template function based on your node’s ports.
3

Understand the template

The editor provides a template function with your ports as parameters:
def main(input_port, output_port):
    # Your code here
    pass
The function signature matches your node’s ports. Input ports become function parameters for receiving data, and output ports become parameters for sending data.
4

Receive data from inputs

Read data from input ports:
def main(temperature_in, temperature_out):
    # Receive data from input port
    reading = temperature_in.receive()
    
    # Process the data
    # ... (your logic here)
The receive() method blocks until data is available. For non-blocking reads, use try_receive() (if available in your language).
5

Process the data

Write your business logic to process the received data:
def main(temperature_in, temperature_out):
    reading = temperature_in.receive()
    
    # Convert Celsius to Fahrenheit: F = (C * 9/5) + 32
    fahrenheit = (reading.celsius * 9.0 / 5.0) + 32.0
    
    # Create output reading
    output = TemperatureReading(
        timestamp=reading.timestamp,
        celsius=fahrenheit  # Store in celsius field
    )
This is where you implement your node’s core functionality. Keep it focused on a single responsibility.
6

Send data to outputs

Send the processed data through output ports:
def main(temperature_in, temperature_out):
    reading = temperature_in.receive()
    fahrenheit = (reading.celsius * 9.0 / 5.0) + 32.0
    output = TemperatureReading(timestamp=reading.timestamp, celsius=fahrenheit)
    
    # Send data to output port
    temperature_out.send(output)
The send() method publishes data to the topic connected to that output port. All subscribers to that topic will receive the data.
7

Handle errors

Add error handling for robustness:
def main(temperature_in, temperature_out):
    try:
        reading = temperature_in.receive()
        fahrenheit = (reading.celsius * 9.0 / 5.0) + 32.0
        output = TemperatureReading(timestamp=reading.timestamp, celsius=fahrenheit)
        temperature_out.send(output)
    except Exception as e:
        print(f"Error processing temperature: {e}")
Always handle errors gracefully. Don’t let one bad message crash your entire pipeline.
8

Save the code

Click Save (or press Ctrl+S / Cmd+S) to save your code.
The code should save without errors. If there are syntax errors, the editor will highlight them.

Code Patterns

Publisher Node (No Inputs)

Nodes that generate data:
def main(output_port):
    # Generate data
    data = generate_data()
    output_port.send(data)

Processor Node (Input and Output)

Nodes that transform data:
def main(input_port, output_port):
    data = input_port.receive()
    processed = process(data)
    output_port.send(processed)

Subscriber Node (No Outputs)

Nodes that consume data:
def main(input_port):
    data = input_port.receive()
    log_data(data)  # Or display, store, etc.

Best Practices

Single Responsibility

Each node should do one thing well. If a node is doing too much, consider splitting it.

Error Handling

Always handle errors gracefully. Don’t let one bad message crash your pipeline.

Non-Blocking

Keep node code fast and non-blocking. Avoid long-running operations that block execution.

Clear Logic

Write clear, readable code. Future you (and your team) will appreciate it.

Troubleshooting

Problem: Code has syntax errors and won’t save.Solutions:
  • Check language-specific syntax (Rust/Python/C++ have different rules)
  • Verify brackets, parentheses, and semicolons are balanced
  • Use the editor’s syntax highlighting to spot errors
  • Check for typos in variable and function names
Problem: Code references types that don’t exist.Solutions:
  • Verify schemas are defined and loaded
  • Check that port types match schema names exactly
  • Ensure schema files are saved and valid
  • Try refreshing the project to reload schemas
Problem: Code references a port that doesn’t exist.Solutions:
  • Verify the port exists on the node
  • Check that port names match exactly (case-sensitive)
  • Ensure ports are saved before writing code
  • Check the function signature matches your ports

Next Steps

Now that you can write node code, learn more: