4 releases
new 0.0.4 | Apr 19, 2025 |
---|---|
0.0.3 | Apr 19, 2025 |
0.0.2 | Apr 17, 2025 |
0.0.1 | Apr 4, 2025 |
#203 in Debugging
188 downloads per month
185KB
4K
SLoC
Phlow
Modular Flow Runtime for Composable Backends
Phlow is a high-performance, scalable, and Low Code flow runtime built with Rust — designed to revolutionize the way you build backends. With Phlow, you can create APIs, automations, and event-driven systems using just YAML, JSON, or TOML, composing logic like building blocks.
Thanks to its modular architecture and clear separation between control and behavior, Phlow lets you orchestrate complex flows without writing code — and when you need more power, just plug in lightweight scripts or Rust modules.
It also comes with native observability powered by OpenTelemetry, giving you full visibility into your flows, modules, and executions. Easily export traces and metrics to Jaeger, Grafana Tempo, or AWS X-Ray, all with simple environment variables.
If you're looking for speed, flexibility, and full insight into your backend — Phlow is the Low Code revolution you’ve been waiting for.
📚 Table of Contents
- 🎯 Philosophy
- 🔌 Module Types
- 🧱 Example:
main.yaml
for an HTTP Gateway - 🧩 YAML Superpowers
- ⚙️ Install & Usage
- 🧠 Creating Your Own Module:
log
- 📦 Project Structure
- 📡 Observability
- 🧪 OpenTelemetry + Jaeger (Local Dev Setup)
- 🌍 Environment Settings
- 📜 License
🎯 Philosophy
Phlow was built around the following principles:
1. Flow over Frameworks
Forget bulky frameworks. Phlow embraces flows. Each step is modular, each behavior is pluggable. You define what happens, when, and how — all through configuration and small, focused modules.
2. Composability
Phlow encourages building small pieces that fit together. Each module can:
- Run logic (
step module
) - Start the system (
main module
) - Interact via
input
andoutput
- Be swapped, reused, or extended easily.
3. Extensibility with Scripts
Need logic? Use phs
(Phlow Script) or rhai
. Define logic inline or in external files. You don't need to recompile to change behavior — just change the YAML.
4. Observability First
Every module, flow, and step can be traced using tracing
and OpenTelemetry. You'll always know where, why, and how something happened.
5. Separation of Control and Behavior
Control lives in YAML (steps
, conditions
, includes
). Behavior lives in modules and scripts. You can mix and match at will.
🔌 Module Types
Type | Purpose |
---|---|
main module |
Entry point. Starts the app (HTTP, CLI, AMQP, etc). |
step module |
Logic executed within a flow (log, fetch, transform, etc). |
🧱 Example: main.yaml
for an HTTP Gateway
main: gateway
modules:
- name: gateway
module: rest_api
with:
host: 0.0.0.0
port: 3000
- name: request
module: http_request
with:
timeout: 29000 # 29s
steps:
- condition:
assert: !eval main.path.start_with("/public")
then:
module: request
input:
method: !eval main.method
url: !eval `public-service.local${main.uri}?`
headers:
x-forwarded-for: !eval main.client_ip
x-original-path: !eval main.path
body: !eval main.body
- use: authorization
id: auth
input:
api_key: !eval main.header.authorization
- condition:
assert: !eval steps.auth.authorized == true
then:
module: request
with:
method: !eval main.method
url: !eval `private-service.local${main.uri}?`
headers:
x-forwarded-for: !eval main.client_ip
x-original-path: !eval main.path
body: !eval main.body
- return:
status_code: 401
body: {
"message": "unauthorized",
"code": 401
}
🧩 YAML Superpowers
Phlow extends YAML with:
!eval
: execute inline expressions using Phlow Script (phs).!include
: include other YAML files into the flow tree.!import
: import external script files (.phs or .rhai) and evaluate them with!eval
.
⚙️ Installation & Usage
Install Phlow globally using Cargo:
cargo install phlow-runtime
🔧 Running a Flow
By default, Phlow will look for a `main.yaml` in the current directory:
phlow
To run a specific file:
phlow path/to/your-flow.yaml
If you provide a directory path and it contains a `main.yaml`, Phlow will automatically run that:
phlow path/to/directory
# → runs path/to/directory/main.yaml
🆘 Help
For all available options and usage info:
phlow -h
# or
phlow --help
🧠 Creating Your Own Module: log
Phlow modules are written in Rust and compiled as shared libraries. Here’s a real example of a simple log module that prints messages at various log levels.
🔧 Code (src/lib.rs
)
use phlow_sdk::{
crossbeam::channel,
modules::ModulePackage,
prelude::*,
tracing::{debug, error, info, warn},
};
plugin!(log);
enum LogLevel {
Info,
Debug,
Warn,
Error,
}
struct Log {
level: LogLevel,
message: String,
}
impl From<&Value> for Log {
fn from(value: &Value) -> Self {
let level = match value.get("level") {
Some(level) => match level.to_string().as_str() {
"info" => LogLevel::Info,
"debug" => LogLevel::Debug,
"warn" => LogLevel::Warn,
"error" => LogLevel::Error,
_ => LogLevel::Info,
},
_ => LogLevel::Info,
};
let message = value.get("message").unwrap_or(&Value::Null).to_string();
Self { level, message }
}
}
pub fn log(setup: ModuleSetup) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let (tx, rx) = channel::unbounded::<ModulePackage>();
setup.setup_sender.send(Some(tx)).ok();
for package in rx {
let log = match package.context.input {
Some(value) => Log::from(&value),
_ => Log {
level: LogLevel::Info,
message: "".to_string(),
},
};
match log.level {
LogLevel::Info => info!("{}", log.message),
LogLevel::Debug => debug!("{}", log.message),
LogLevel::Warn => warn!("{}", log.message),
LogLevel::Error => error!("{}", log.message),
}
sender_safe!(package.sender, Value::Null);
}
Ok(())
}
🛠️ Example usage in a flow
steps:
- id: notify
module: log
with:
level: info
message: "Process started"
- use: log
with:
level: error
message: !eval "something went wrong: " + main.error
📦 Project Structure
you_project/
├── main.yaml
├── modules.yaml
├── assets/
│ └── body.yaml
├── scripts/
│ └── resolve_url.phs
├── phlow_packages/
│ ├── restapi/
│ │ └── module.so
│ ├── request/
│ │ └── module.so
│ └── log/
│ └── module.so
All compiled .so
modules must be placed inside the phlow_packages/
directory.
To build all modules at once, this project includes a utility script:
📡 Observability
Phlow integrates with:
- OpenTelemetry (OTLP)
- Tracing (Spans and Logs)
- Prometheus Metrics
- Jaeger, Grafana Tempo, AWS X-Ray
Enable it with:
PHLOW_OTEL=true
PHLOW_LOG=DEBUG
PHLOW_SPAN=INFO
🧪 OpenTelemetry + Jaeger (Local Dev Setup)
To enable observability with Jaeger during development, you can run a full OpenTelemetry-compatible collector locally in seconds.
🔄 1. Run Jaeger with OTLP support
docker run -d \
-p4318:4318 \ # OTLP HTTP
-p4317:4317 \ # OTLP gRPC
-p16686:16686 \ # Jaeger UI
jaegertracing/all-in-one:latest
This container supports OTLP over HTTP and gRPC, which are both compatible with Phlow's OpenTelemetry output.
⚙️ 2. Configure environment variables
Set the following environment variables in your shell or .env
file:
export OTEL_RESOURCE_ATTRIBUTES="service.name=phlow-dev,service.version=0.1.0"
export OTEL_SERVICE_NAME="phlow-dev"
🔍 3. Open the Jaeger UI
Once running, access the Jaeger web interface at:
Search for your service using the name defined in OTEL_SERVICE_NAME
.
✅ Tips
- Combine this with
PHLOW_OTEL=true
,PHLOW_SPAN=INFO
, andPHLOW_LOG=DEBUG
for full observability. - You can also integrate with Grafana Tempo or AWS X-Ray by replacing the collector backend.
🌍 Environment Settings
Below is a list of all environment variables used by the application, combining those defined in both files, along with their descriptions, default values, and types.
Environment Variables Table
Variable | Description | Default Value | Type |
---|---|---|---|
PHLOW_PACKAGE_CONSUMERS_COUNT | Number of package consumers Defines how many threads will be used to process packages. |
10 |
i32 |
PHLOW_MIN_ALLOCATED_MEMORY_MB | Minimum allocated memory (MB) Defines the minimum amount of memory, in MB, allocated to the process. |
10 |
usize |
PHLOW_GARBAGE_COLLECTION_ENABLED | Enable garbage collection Enables or disables garbage collection (GC). |
true |
bool |
PHLOW_GARBAGE_COLLECTION_INTERVAL_SECONDS | Garbage collection interval (seconds) Defines the interval at which garbage collection will be performed. |
60 |
u64 |
PHLOW_LOG | Log level Defines the log verbosity for standard logging output. Possible values typically include TRACE , DEBUG , INFO , WARN , ERROR . |
WARN |
str |
PHLOW_SPAN | Span level Defines the verbosity level for span (OpenTelemetry) tracing. Possible values typically include TRACE , DEBUG , INFO , WARN , ERROR . |
INFO |
str |
PHLOW_OTEL | Enable OpenTelemetry Enables or disables OpenTelemetry tracing and metrics. |
true |
bool |
Notes
- If an environment variable is not set, the default value indicated in the table above will be used.
- Set the corresponding environment variables before running the application to override the defaults.
- The log level (
PHLOW_LOG
) and span level (PHLOW_SPAN
) control different layers of logging:PHLOW_LOG
: Affects standard logging (e.g., error, warning, info messages).PHLOW_SPAN
: Affects tracing spans (useful for deeper telemetry insights with OpenTelemetry).
- The
PHLOW_OTEL
variable controls whether or not OpenTelemetry providers (for both tracing and metrics) are initialized.
📜 License
MIT © 2025 — Built with ❤️ and Rust.
Dependencies
~31–47MB
~763K SLoC