Skip to content

zjn-zjn/ice

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

405 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ice

Ice

A lightweight, zero-dependency rule engine with visual tree-based orchestration

GitHub Stars GitHub Release License Maven Central Go Reference PyPI Docker Pulls

Documentation · Live Demo · Getting Started · Changelog

中文


What is Ice?

Ice is a rule engine that takes a fundamentally different approach: rules are organized as trees, not chains or tables. Each node in the tree handles its own logic independently — modifying one node never creates cascading effects on others. Nodes communicate exclusively through a shared, thread-safe data context called Roam, rather than referencing each other directly.

The result is a system where business rules can be visually configured, hot-reloaded in seconds, and executed in-memory with sub-millisecond latency — all without requiring any database or middleware.

Key Features

Feature Description
Tree-Based Orchestration Rules organized as trees — nodes are independent, changes to one node never cascade to others
Visual Web Editor Configure rules through an intuitive web UI with a tree editor, no DSL to learn
Zero Dependencies No database, no message queue, no service registry — just files on disk
Multi-Language SDKs Java, Go, and Python with full feature parity
Hot Reload Changes take effect in seconds via automatic version polling — no restart needed
High Performance Pure in-memory execution with sub-millisecond latency, zero network overhead
Node Reuse Same node can be shared across multiple rule trees
Parallel Execution Built-in parallel relation nodes for concurrent child execution
Mock Debugging Trigger rule execution remotely from the Web UI for real-time debugging
Lane / Traffic Isolation Branch-based rule isolation for A/B testing, canary releases, and gradual rollouts

How It Works

Rule Trees

Every rule in Ice is a tree composed of two types of nodes:

  • Relation Nodes — control the execution flow (similar to logical operators)
  • Leaf Nodes — contain your actual business logic

Relation Nodes (Control Flow)

Type Behavior Short-Circuit
AND All children must return true Yes
ANY At least one child returns true Yes
ALL All children must return true No
NONE No child returns true No
TRUE Always returns true (execute all children for side effects) No

Each type has a parallel variant (P_AND, P_ANY, P_ALL, P_NONE, P_TRUE) that executes children concurrently.

Leaf Nodes (Business Logic)

Type Return Purpose
Flow boolean Conditional checks — "Is the user eligible?"
Result boolean Business operations — "Issue the coupon"
None void Side effects — queries, logging, metrics, notifications

Roam (Data Context)

Roam is the thread-safe data container that flows through the entire rule tree. Nodes read input from and write output to Roam — they never reference each other directly. This is the key to node isolation.

Roam
├── put("uid", 12345)              // flat key-value
├── putDeep("user.level", "gold")  // nested key
├── get("uid")                     // → 12345
└── getDeep("user.level")          // → "gold"
  • Thread-safe: Java ConcurrentHashMap / Go sync.RWMutex / Python threading.RLock
  • Deep keys: putDeep("a.b.c", value) auto-creates nested structures
  • Dynamic references: prefix a value with @ to resolve it from Roam at runtime (e.g., @uid reads roam.get("uid"))

Architecture

┌──────────────────────────────────────────────────────────────┐
│                   Shared Storage (ice-data/)                 │
│     ┌────────┐    ┌────────┐    ┌────────┐    ┌──────────┐  │
│     │ apps/  │    │ bases/ │    │ confs/ │    │ versions/│  │
│     └────────┘    └────────┘    └────────┘    └──────────┘  │
└──────────────────────────────────────────────────────────────┘
          ▲                                       ▲
          │ Write                                 │ Read (Poll)
          │                                       │
┌─────────┴─────────┐                 ┌───────────┴───────────┐
│    Ice Server      │                │      Ice Client       │
│                    │                │                       │
│  • Web UI          │                │  • Version polling    │
│  • Tree editor     │                │  • Hot reload         │
│  • Apply & publish │                │  • In-memory exec     │
│  • Mock debugging  │                │  • Mock execution     │
│                    │                │  • Fault tolerant     │
└────────────────────┘                └───────────────────────┘

Key design decisions:

  • Server and Client are fully decoupled — if the Server goes down, Clients continue executing rules from their in-memory cache
  • File-based communication — no network protocol between Server and Client, just a shared directory (ice-data/)
  • Incremental updates — Client polls versions/ for changes and applies only the delta; falls back to full reload if incremental files are missing

Deployment Options

Mode Description
Single Machine Server + Client on the same host, ice-data/ is a local directory
Docker Compose Containerized deployment with volume mounts
Distributed Multiple Servers/Clients sharing storage via NFS, AWS EFS, or GCP Filestore

Quick Start

1. Deploy the Server

docker run -d --name ice-server -p 8121:8121 \
  -v ./ice-data:/app/ice-data waitmoon/ice-server:latest

Open http://localhost:8121 to access the Web UI.

2. Install the Client SDK

Java
<dependency>
  <groupId>com.waitmoon.ice</groupId>
  <artifactId>ice-core</artifactId>
  <version>4.0.9</version>
</dependency>
Go
go get github.com/zjn-zjn/ice/sdks/go
Python
pip install ice-rules

3. Define Your Leaf Nodes

Leaf nodes are where your business logic lives. Here's a simple ScoreFlow that checks if a value meets a threshold:

Java
@Data
@EqualsAndHashCode(callSuper = true)
public class ScoreFlow extends BaseLeafFlow {

    private double score;
    private String key;

    @Override
    protected boolean doFlow(IceRoam roam) {
        Number value = roam.getDeep(key);
        if (value == null) {
            return false;
        }
        return value.doubleValue() >= score;
    }
}
Go
type ScoreFlow struct {
    Score float64 `json:"score" ice:"name:Score Threshold,desc:Minimum score to pass"`
    Key   string  `json:"key" ice:"name:Roam Key,desc:Key to read from Roam"`
}

func (s *ScoreFlow) DoFlow(ctx context.Context, roam *icecontext.Roam) bool {
    value := roam.ValueDeep(s.Key).Float64Or(0)
    return value >= s.Score
}

Register it:

ice.RegisterLeaf("com.example.ScoreFlow",
    &ice.LeafMeta{Name: "Score Check", Desc: "Check if score meets threshold"},
    func() any { return &ScoreFlow{} })
Python
@ice.leaf("com.example.ScoreFlow", name="Score Check", desc="Check if score meets threshold")
class ScoreFlow:
    score: Annotated[float, IceField(name="Score Threshold")] = 0.0
    key: Annotated[str, IceField(name="Roam Key")] = ""

    def do_flow(self, roam: Roam) -> bool:
        value = roam.get_deep(self.key)
        if value is None:
            return False
        return float(value) >= self.score

4. Initialize the Client and Execute

Java
// Initialize
IceFileClient client = new IceFileClient(1, "./ice-data", "com.your.package");
client.start();

// Execute
IceRoam roam = IceRoam.create();
roam.setId(1L);
roam.put("uid", 12345);
roam.put("score", 95.5);
Ice.syncProcess(roam);
Go
// Initialize
client, _ := ice.NewClient(1, "./ice-data")
client.Start()
defer client.Destroy()

// Execute
roam := ice.NewRoam()
roam.SetId(1)
roam.Put("uid", 12345)
roam.Put("score", 95.5)
ice.SyncProcess(context.Background(), roam)
Python
# Initialize
client = ice.FileClient(app=1, storage_path="./ice-data")
client.start()

# Execute
roam = ice.Roam.create()
roam.set_id(1)
roam.put("uid", 12345)
roam.put("score", 95.5)
ice.sync_process(roam)

5. Configure Rules in the Web UI

Open the Web UI → create a rule tree → arrange your nodes → click Apply. Changes take effect within seconds — no restart required.

Comparison with Traditional Rule Engines

Ice Traditional (Drools, etc.)
Learning Curve 5 minutes — visual configuration, no DSL Requires learning rule language syntax
Deployment Docker one-click, zero external dependencies Requires database + middleware setup
Configuration Web UI tree editor Text/code-based rule files
Performance In-memory, sub-millisecond latency Compilation and interpretation overhead
Hot Reload Seconds, automatic — no restart Often requires application restart
Change Impact Node-isolated — changes affect only that node Cascading effects across rule chains
Ops Complexity Single binary + file directory Multi-component infrastructure

Use Cases

Scenario Examples
Marketing Campaigns Coupons, discounts, promotions, group deals, flash sales
Risk Control Credit assessment, anti-fraud detection, real-time risk evaluation
Dynamic Pricing Price strategies, discount rules, tiered pricing, surge pricing
Access Control Permission management, feature flags, role-based access
Process Orchestration Approval workflows, order processing, ticket routing, state machines

Configuration Reference

Client Configuration

Parameter Required Default Description
app Yes Application ID
storagePath Yes Path to shared ice-data/ directory
scan Java only Package path for automatic node scanning
pollInterval No 2s How often to check for version changes
heartbeatInterval No 10s Heartbeat reporting interval
parallelism No ForkJoinPool Thread pool size for parallel nodes
lane No Lane name for traffic isolation / branch testing

Server Configuration

Parameter Default Description
port 8121 Server HTTP port
storage-path ./ice-data File storage directory
mode open open (normal) or controlled (read-only UI)
client-timeout 30s Client inactivity timeout
version-retention 1000 Number of version files to retain
publish-targets Remote server addresses for multi-instance publishing

Documentation

Guide

  • Getting Started — Deploy, integrate, and run your first rule
  • Core Concepts — Trees, nodes, Roam, and execution model
  • Architecture — Design decisions and deployment patterns
  • FAQ — Common questions and troubleshooting

Reference

SDK Guides

Community

Contributing

Contributions are welcome! Whether it's bug reports, feature requests, documentation improvements, or code contributions — feel free to open an issue or submit a pull request.

License

Apache License 2.0

About

Rule engine/process engine, committed to solving flexible and complex hard-coded problems, for complex/flexibly changing business, provide a new abstract orchestration solution that is lightweight, high-performance and provides visual operation pages. Java规则引擎-ice,针对复杂/灵活变动业务,提供一个新的抽象编排解决方案,轻量级,高性能并提供可视化操作页面

Topics

Resources

License

Stars

Watchers

Forks

Contributors