Delete page "Process-Streaming.-"
parent
64c265b440
commit
716b18f69d
1 changed files with 0 additions and 136 deletions
|
|
@ -1,136 +0,0 @@
|
|||
# Process Streaming
|
||||
|
||||
The `go-ws` package provides two convenience methods for streaming process output and status updates over WebSocket channels. These are the primary integration point between a process manager and connected web frontends.
|
||||
|
||||
## SendProcessOutput
|
||||
|
||||
Streams a single line of process output to all clients subscribed to the `process:{id}` channel.
|
||||
|
||||
```go
|
||||
func (h *Hub) SendProcessOutput(processID string, output string) error
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `processID` -- unique identifier for the process (e.g. `"web-server-1"`)
|
||||
- `output` -- a single line of stdout/stderr output
|
||||
|
||||
**Wire format:**
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "process_output",
|
||||
"channel": "process:web-server-1",
|
||||
"processId": "web-server-1",
|
||||
"data": "2026-02-19 10:00:00 Listening on :8080",
|
||||
"timestamp": "2026-02-19T10:00:00.123Z"
|
||||
}
|
||||
```
|
||||
|
||||
**Example -- forwarding output from an exec.Cmd:**
|
||||
|
||||
```go
|
||||
scanner := bufio.NewScanner(cmd.Stdout)
|
||||
for scanner.Scan() {
|
||||
hub.SendProcessOutput("web-server-1", scanner.Text())
|
||||
}
|
||||
```
|
||||
|
||||
## SendProcessStatus
|
||||
|
||||
Sends a process lifecycle status change to all clients subscribed to the `process:{id}` channel.
|
||||
|
||||
```go
|
||||
func (h *Hub) SendProcessStatus(processID string, status string, exitCode int) error
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `processID` -- unique identifier for the process
|
||||
- `status` -- status string (e.g. `"running"`, `"exited"`, `"crashed"`, `"stopped"`)
|
||||
- `exitCode` -- the process exit code (0 for success, non-zero for failure; use 0 for non-exit statuses like `"running"`)
|
||||
|
||||
**Wire format:**
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "process_status",
|
||||
"channel": "process:proc-1",
|
||||
"processId": "proc-1",
|
||||
"data": {
|
||||
"status": "exited",
|
||||
"exitCode": 0
|
||||
},
|
||||
"timestamp": "2026-02-19T10:05:00.456Z"
|
||||
}
|
||||
```
|
||||
|
||||
## Integration with Core Framework
|
||||
|
||||
The hub integrates with the Core framework's action/message-passing system. Process managers dispatch actions, and a registered action handler forwards them to the WebSocket hub:
|
||||
|
||||
```go
|
||||
core.RegisterAction(func(c *framework.Core, msg framework.Message) error {
|
||||
switch m := msg.(type) {
|
||||
case process.ActionProcessOutput:
|
||||
hub.SendProcessOutput(m.ID, m.Line)
|
||||
case process.ActionProcessExited:
|
||||
hub.SendProcessStatus(m.ID, "exited", m.ExitCode)
|
||||
case process.ActionProcessStarted:
|
||||
hub.SendProcessStatus(m.ID, "running", 0)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
```
|
||||
|
||||
This decouples process management from WebSocket delivery. The process manager only needs to emit actions; the WebSocket layer handles fan-out to subscribed clients.
|
||||
|
||||
## Client-Side Consumption
|
||||
|
||||
A JavaScript client subscribes to a process channel and handles the two message types:
|
||||
|
||||
```javascript
|
||||
const socket = new WebSocket("ws://localhost:8080/ws");
|
||||
|
||||
const processId = "web-server-1";
|
||||
|
||||
socket.onopen = () => {
|
||||
socket.send(JSON.stringify({
|
||||
type: "subscribe",
|
||||
data: "process:" + processId
|
||||
}));
|
||||
};
|
||||
|
||||
socket.onmessage = (event) => {
|
||||
const msg = JSON.parse(event.data);
|
||||
|
||||
switch (msg.type) {
|
||||
case "process_output":
|
||||
terminal.appendLine(msg.data);
|
||||
break;
|
||||
case "process_status":
|
||||
statusBadge.textContent = msg.data.status;
|
||||
if (msg.data.exitCode !== 0) {
|
||||
statusBadge.classList.add("error");
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Channel Routing
|
||||
|
||||
Both methods route through `SendToChannel` with the channel name `"process:" + processID`. See [[Channel-Subscriptions]] for details on how channel delivery works.
|
||||
|
||||
If no clients are subscribed to the process channel, the message is silently discarded (no error returned). This means it is safe to call `SendProcessOutput` at high frequency even when no frontends are connected.
|
||||
|
||||
## Backpressure
|
||||
|
||||
If a client's send buffer (capacity 256) is full, that client is skipped for the current message. The message is not queued or retried. For high-throughput process output, this means slow consumers may miss lines.
|
||||
|
||||
The `SendToChannel` path does **not** schedule the client for unregistration when the buffer is full (unlike the `Broadcast` path). The client remains connected and will receive the next message if buffer space is available.
|
||||
|
||||
## Related Pages
|
||||
|
||||
- [[Home]] -- Overview and quick start
|
||||
- [[Architecture]] -- Hub internals and goroutine model
|
||||
- [[Message-Types]] -- Wire format and message type constants
|
||||
- [[Channel-Subscriptions]] -- Channel pub/sub mechanics
|
||||
Loading…
Add table
Reference in a new issue