Processes
Effection 3.0 does not ship with a process library out of the box, but what it does do is make writing resources so easy, that you can do it yourself.
Operating system processes are a perfect candidate for modeling as a resource because they match the resource criteria which are:
- They are long running
- We want to be able to interact with them while they are running.
This section provides a sketch of how you might create a "command" resource for both Deno and Node that will run an operating system command, and then make sure that no matter what happens, that command is shut down properly.
// use-command
import { action, resource, spawn, suspend, createSignal } from "effection";
import { spawn as spawnChild} from "node:child_process";
export function useCommand(...args) {
  return resource(function*(provide) {
    // spawn the OS process
    let proc = spawnChild(...args);
    let stdout = createSignal();
    let stderr = createSignal();
    // create a task that finishes the process finishes
    let exit = yield* spawn(function*() {
      // get the exit code
      let code = yield* action(function*(resolve) {
        proc.on("exit", resolve);
        try {
          yield* suspend();
        } finally {
          proc.off("exit", resolve);
        }
      });
      // close stdin, stdout
      stdout.close();
      stderr.close();
      // return the exitcode
      return code;
    })
    // connect stdin, stdout to signals
    proc.stdout.on("data", stdout.send);
    proc.stderr.on("data", stderr.send);
    try {
      // provide the resource handle
      yield* provide({ exit, stdout, stderr });
    } finally {
      proc.stdout.off("data", stdout.send);
      proc.stderr.off("data", stderr.send);
      proc.kill("SIGINT");
      // wait until the process is fully exited
      yield* exit;
    }
  });
}
using a command
We can now use this command resource to create a process and stream its stdout to the console:
import { main, each } from "effection";
import { useCommand } from "./use-command.mjs";
await main(function*() {
  let ls = yield* useCommand("ls", ["-lh"]);
  for (let data of yield* each(ls.stdout)) {
    console.log(`stdout: ${data}`);
    yield* each.next();
  }
  console.log(`exit: ${yield* ls.exit}`)
});