Skip to main content
Version: 3.0.0

Architecture Overview

This document describes the system design of SeaTunnel Edge Agent: boundaries, data flow, durability, and integration with the engine. For installation, agent.yaml parameters, and day-to-day operations, see Edge Agent.

1. Background and Goals​

1.1 Problem Background​

In many production networks, the Zeta cluster cannot directly access edge-local files (including application logs and NDJSON paths on disk). A dedicated edge collector process is needed to:

  • read local records close to the source,
  • tolerate intermittent network connectivity,
  • deliver data into a running SeaTunnel pipeline without embedding engine workers at edge sites.

1.2 Design Goals​

SeaTunnel Edge Agent is designed with:

  1. Independent deployment: packaging and lifecycle are decoupled from engine workers; the agent runs as an independent process on edge hosts. See Edge Agent — Deployment Guide for install layout.
  2. Durable outbound buffering: WAL-backed outbound queue with explicit state transitions.
  3. Protocol alignment with Zeta: reuse the EdgeSocket line protocol (__AUTH__ / __BATCH__ → RECEIVED); see EdgeSocket source connector.
  4. Simple operations: YAML configuration and predictable scheduler loop; operational detail lives in Edge Agent.
  5. Clear boundaries: sending path and delivery semantics are explicitly bounded for stable operations and extensibility.

1.3 Architecture Positioning​

AspectEdge AgentSeaTunnel Engine
Runtime locationEdge host processCluster coordinator and worker tasks
Input accessLocal files on the edge host (glob paths, including log files)Connector-reachable systems (databases, messaging, object storage, etc.)
Durability and stateLocal WAL outbound queue and input position storeCheckpointing, job state, and task-level recovery
Network roleDials Engine EdgeSocket ingress endpointExposes ingress and orchestrates internal task execution
Primary roleEdge data ingest and forwardingEnd-to-end data integration and pipeline execution

1.4 Responsibility Boundaries​

To keep architecture decisions explicit, treat these boundaries as stable contracts:

BoundaryOwned by Edge AgentOwned by Engine / Job
Durability boundaryPersist local outbound rows and retry until the engine returns RECEIVEDDurable processing after ingest is accepted
Checkpoint boundaryNot checkpoint-aware in this release (__COMMIT__ not used)Checkpoint lifecycle and exactly-once semantics
Failure ownershipLocal file read, local WAL state, transport reconnect behaviorSource ingress policy, downstream transform/sink correctness

2. Logical Architecture​

2.1 Deployment Topology​

┌─────────────────────────────────────────────────────────────────┐
│ Edge host │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Edge Agent process │ │
│ │ Input collector ──► Scheduler & batching │ │
│ │ │ │ │ │
│ │ │ ├──► Outbound queue (WAL) │ │
│ │ └──► Input position store (local persistence) │ │
│ │ │ │ │
│ │ └──► Transport client │ │
│ └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
│ TCP line protocol
▼
┌─────────────────────────────────────────────────────────────────┐
│ SeaTunnel Engine (Zeta) │
│ EdgeSocket Source ingress at configured output.endpoint │
└─────────────────────────────────────────────────────────────────┘

Trust boundary: the agent trusts local filesystem access and its own local persistent stores. The engine trusts the configured output.token on __AUTH__. There is no automatic cluster endpoint discovery; output.endpoint is configured statically.

2.2 Data Plane​

Records move through the agent on a single-threaded scheduler loop:

Control plane (configuration load, plugin selection, lifecycle start/stop) runs once at startup and on shutdown; the hot path above is the data plane.

2.3 Repository Modules​

Implementation is split into three Maven modules (names for repository navigation only):

LayerResponsibilityModule
Runtime coreYAML resolution, process lifecycle, scheduler loop, outbound queue and input position persistenceseatunnel-edge-agent-starter
Transport and encodingEdgeSocket or console sink, reconnect policy, raw/packet payload modesseatunnel-edge-agent-transport
Input pluginsFile collector, NDJSON normalization, multiline assemblyseatunnel-edge-agent-connector

Distribution packaging is produced by seatunnel-dist edge-agent assemblies; see Download.

3. Runtime Behavior​

3.1 Startup and Shutdown​

On graceful shutdown, the scheduler drains any in-memory batch into the outbound queue before exit so records are not lost in RAM.

3.2 Main Loop​

Each iteration of the scheduler loop:

  1. Poll input — read up to queue.poll-batch-size events from the configured input collector (input.*).
  2. Buffer in memory — accumulate events until agent.bulk-max-size or agent.flush-interval-ms.
  3. Flush to persistence — append events to the outbound queue as PENDING rows; persist input positions from each event (file offset / line metadata).
  4. Send outbound — claim pending rows, encode payload, send via transport; on RECEIVED, mark rows ACKED.
  5. Housekeeping — mark exhausted PENDING rows as DEAD, resurrect SENDING rows, delete acknowledged rows per queue.acked-retention-ms, sleep agent.idle-sleep-ms when idle.

3.3 Outbound Queue State Machine​

Each outbound record transitions:

PENDING
│ claim for send (attempt_count++)
▼
SENDING
│ send success + engine RECEIVED
├──────────────► ACKED
│
└ send failure / timeout / crash before RECEIVED
▼
PENDING (attempt counter increased; via resurrect)
│
└ attempt_count >= retry.max-attempts
▼
DEAD (no further sends; operator cleanup)

resurrect periodically moves SENDING rows back to PENDING so a crash between claim and RECEIVED does not strand data. retry.max-attempts stops claiming rows that exceeded the limit; markExceededAsDead moves them to DEAD.

File positions are persisted when events are appended to the outbound queue (same flush as WAL insert), not when the engine acknowledges a batch. Recovery relies on WAL rows plus saved input positions.

4. Outbound Queue and Input Positions​

The agent maintains two separate local persistence concerns:

StorePurposeUpdated whenRecovery after restart
Outbound queueDurability until the engine returns RECEIVED for a batchEvents are flushed from memory; rows move PENDING → SENDING → ACKEDSENDING rows revert to PENDING; unsent data is retried
Input position storeResume reading local files without re-reading already persisted eventsSame flush as outbound append (per-event position)Collector reopens at saved byte offset / line

Keeping them separate avoids coupling “what was sent to the network” with “where to read next on disk.” A network outage should not reset file tail positions; conversely, advancing a file cursor must not imply the remote pipeline has committed data.

The agent persists outbound records and position records in local persistent storage: outbound records drive retryable sends, and position records support resume recovery.

5. Network and EdgeSocket Contract​

5.1 Endpoint Model​

The transport client connects to the statically configured output.endpoint (host:port). There is no cluster service discovery. Changing the ingest host requires updating configuration and restarting the agent.

5.2 Wire Protocol​

The agent implements the collector side of EdgeSocket. It does not send __COMMIT__. Durability on the agent is the WAL row ACKED state after RECEIVED, not engine checkpoint polling.

StepAgent → EngineEngine → AgentAgent handling
Auth__AUTH__:<token>ACK / AUTH_FAILED / REJECTEDREJECTED: fail fast, no auto-reconnect (duplicate collector)
Batch__BATCH__:<batchId>:<payload>RECEIVED / RETRY / QUEUE_FULL:<ms> / DECRYPT_FAILEDQUEUE_FULL: wait and resend; DECRYPT_FAILED: fatal configuration error
ACK and RECEIVED

ACK belongs to authentication. RECEIVED belongs to batch ingest and is the only success response that advances a WAL row from SENDING to ACKED.

batchId is the WAL row batch_id used on the wire (__BATCH__:<batchId>:...), allocated from edge_agent_meta.next_batch_id and monotonic for that agent database. It is not the WAL row primary key id.

5.3 Reconnect Policy​

On I/O failures (and retryable transport-level failures):

  1. invalidate the current socket session,
  2. retry configured endpoint candidates (typically one static host),
  3. reconnect, re-authenticate, and resume claiming pending outbound rows. Transport reconnect backoff follows output. transport settings; scheduler replay pacing follows retry..

5.4 Protocol Contract vs Implementation Detail​

Stable protocol contract:

  • The agent authenticates with __AUTH__:<token> and sends __BATCH__:<batchId>:<payload>.
  • RECEIVED acknowledges ingest acceptance for that batch.
  • The agent does not send __COMMIT__ in this release.

Current runtime behavior:

  • batchId is persisted as WAL row batch_id and allocated from edge_agent_meta.next_batch_id.
  • Runtime uses a single scheduler loop for sending.

6. Reliability and Delivery Semantics​

6.1 Failure Scenarios​

FailureBehavior
Agent process crashSENDING outbound rows restored to PENDING on restart; in-memory batch lost unless graceful shutdown drained it
Temporary network outageRow stays SENDING on send failure; scheduler backs off; resurrectSending moves stale SENDING rows back to PENDING, then reconnect and retry
Collector endpoint changeUpdate output.endpoint and restart agent
Graceful shutdownIn-memory batch flushed to outbound queue before exit

6.2 Delivery mode​

When agent.delivery-guarantee is not configured, it defaults to BEST_EFFORT.

BEST_EFFORT (default)​

  • The agent keeps a local WAL outbound queue and retries until the engine returns RECEIVED (or the row is marked DEAD after retry.max-attempts).
  • The same WAL row may be sent more than once after failures, crashes between claim and RECEIVED, resurrectSending, or operator db wal-retry-dead.
  • The agent does not send __COMMIT__; durability ends at engine RECEIVED for a batch.

Design for downstream: treat the output boundary as may deliver duplicates — use idempotent sinks or deduplication keys when you need strict uniqueness. See Configuration — agent.

NON​

  • No WAL or source position persistence — the agent runs completely stateless.
  • Events are read from input, batched in memory, and sent directly via transport. On send failure, the event is dropped with a warning log.
  • On restart, file reading resumes based on input configuration (e.g. read-from-beginning), not saved positions. Previously sent data may be re-read and re-sent.
  • queue.* and retry.* configuration sections are ignored in NON mode.

6.3 Boundary with Engine Checkpointing​

ConcernEdge AgentSeaTunnel Engine
Durability until engine RECEIVEDWAL-backed outbound queue—
Pipeline exactly-once / checkpoint—Checkpoint mechanism on tasks
Commit cursor to agentNot used (__COMMIT__ not sent)—

The agent’s contract ends when the engine returns RECEIVED for a batch. Further correctness is the job’s responsibility.

6.4 Failure-to-Action Runbook​

SymptomPrimary signalLikely ownerFirst action
AUTH_FAILEDAgent transport/auth logAgent + job configAlign output.token and Engine token, then restart agent
REJECTEDAgent transport/auth logDeployment policyCheck duplicate collector identity / listener policy conflict
Growing backlog (PENDING/SENDING)WAL summary and queue depthAgent side firstCheck endpoint reachability, transport retries, and engine ingest pressure
Repeated DEAD rowsWAL status transitionsAgent config + payload compatibilityInspect dead rows, fix root cause, then decide purge vs retry

7. Configuration and Extension​

7.1 Configuration Surface​

Runtime behavior is driven by a single agent.yaml with top-level sections agent, input, queue, retry, and output. A typical deployment configures input (with paths) and production output (transport + endpoint); when queue and retry are not configured, defaults apply (sqlite-path: data/wal.db, built-in retry policy).

For every key, type, default, and validation rule, use the authoritative Edge Agent — Configuration Reference. Example file in the repository and install package: seatunnel-edge-agent/config/agent.yaml under the install root config/ directory.

7.2 Input​

Only the file input is implemented today (input.type defaults to file). Configure input.paths with globs to tail local files; application logs, NDJSON, and rotated log files are all expressed as paths (for example /var/log/*.log). There are no separate log or event input types.

See Input Configuration for parameters and examples. Additional input.type values are SPI extension points via EdgeInputReaderFactory.

7.3 Output and Payload Encoding​

Transport vs console, endpoint alignment with the engine, and RAW vs PACKET scenarios are documented in Output Configuration. Wire-level responses: EdgeSocket Source.

Plugins are selected by input.type and output.type in YAML; adding a new input or transport implementation is an extension point without changing the scheduler contract.