nact

repository·next·Indexed 22 days ago

https://github.com/nactio/nact

A Node.js framework implementing the actor model and event sourcing for server-side applications. Inspired by Akka and Erlang, nact provides tools for stateful programming, including ActorSystem management, supervision policies, and persistent actors via @nact/persistence. It also includes @nact/streams for managing data flow between producers and consumers using a handshake-based protocol and support for Iterable and AsyncIterable sources.

Tokens
1.8K
Snippets
8
Records
13
Agent score
65%

What's inside nact

  1. What is Nact?

    next

    Nact is an open-source Node.js framework inspired by Akka and Erlang. It implements the actor model and provides out-of-the-box support for event sourcing. Nact is designed to help developers manage state in server-side applications to achieve:

    • More effective memory usage
    • Improved application resilience
    • Increased performance
    • Reduced coupling

    Nact is intended for Node.js environments (version 8 and above).

  2. Understand the Stream Protocol (Producer and Consumer)

    next

    Streams in @nact/streams operate using a specific message protocol defined by tuples [Type, Payload].

    Consumer Protocol (ConsumerProtocol<Msg>)

    Messages sent to the consumer:

    • [0, ProducerProtocol<Msg>] (HANDSHAKE): The producer sends its own port to the consumer.
    • [1, Msg] (RECEIVE): The producer sends the actual data payload.
    • [3, Error | undefined] (CLOSE): The producer signals the end of the stream, optionally with an error.

    Producer Protocol (ProducerProtocol<Msg>)

    Messages sent to the producer:

    • [0, ConsumerProtocol<Msg>] (HANDSHAKE): The consumer sends its own port to the producer.
    • [2] (NEXT): The consumer requests the next item.
    • [3, any | undefined] (CLOSE): The consumer signals it wants to stop receiving data.
  3. Create a stream from an Iterable using fromIterable

    next

    The fromIterable function creates a producer from a standard synchronous Generator or Iterable. It returns a function that, when called with a parent (an actor or system), spawns a new actor that manages the iteration.

    When the spawned actor receives:

    • HANDSHAKE: It performs the handshake with the consumer.
    • NEXT: It pulls the next value from the iterator. If the iterator is exhausted, it sends CLOSE to itself. If a value is yielded, it sends RECEIVE to the target.
    • CLOSE: It sends CLOSE to the target and stops itself.
    import { fromIterable } from "@nact/streams";
    
    const myGenerator = (function* () {
      yield "item 1";
      yield "item 2";
    })();
    
    // Returns a function that accepts a parent actor/system
    const producerFactory = fromIterable(myGenerator);
    
    // Spawns the producer actor under the parent
    const producerPort = producerFactory(parentActor);
  4. Spawn actors with spawn and spawnStateless

    next

    Use spawn to create a stateful actor and spawnStateless to create an actor that does not maintain internal state. These functions are the primary way to initialize actors within the Nact system.

    import { spawn, spawnStateless } from '@nact/core';
    
    // Example usage (signatures implied by export):
    // const actor = await spawn(system, name, actorFn, options);
    // const statelessActor = await spawnStateless(system, name, actorFn, options);
  5. Communicate with actors using dispatch and query

    next

    Nact provides two primary ways to interact with an actor:

    • dispatch: Send a message to an actor without expecting a response (fire-and-forget).
    • query: Send a message to an actor and wait for a response (request-response).
    import { dispatch, query } from '@nact/core';
    
    // dispatch(actor, message)
    // query(actor, message)
  6. Create a stream from an AsyncIterable using fromAsyncIterable

    next

    The fromAsyncIterable function creates a producer from an AsyncGenerator or AsyncIterable. It behaves similarly to fromIterable but awaits the .next() calls on the iterator.

    It is useful for streaming data from asynchronous sources like database cursors or network fetches into the Nact actor system.

    import { fromAsyncIterable } from "@nact/streams";
    
    async function* asyncGen() {
      yield await fetchSomeData();
      yield await fetchMoreData();
    }
    
    const producerFactory = fromAsyncIterable(asyncGen());
    const producerPort = producerFactory(parentActor);
  7. Spawn a persistent actor with spawnPersistent

    next

    Use spawnPersistent to create an actor that can persist its state across restarts. This is useful for long-lived actors where state recovery is required after a crash or system restart.

    import { spawnPersistent } from '@nact/persistence';
    
    // Example usage (conceptual):
    const actor = await spawnPersistent({
      name: 'my-persistent-actor',
      props: { /* ... */ },
      // ... other configuration
    });
  8. Initialize and manage an ActorSystem

    next

    An ActorSystem is the top-level container for managing actors and their lifecycles. Use start to initialize a system.

    import { start, ActorSystem } from '@nact/core';
    
    // const system: ActorSystem = await start();
  9. Manage stream lifecycle with open, next, and close

    next

    The @nact/streams package provides functions to control the lifecycle of a stream between a producer and a consumer using a handshake-based protocol.

    • open(port, actor): Initiates the stream by performing a handshake between the provided port (the producer) and the actor (the consumer).
    • next(port): Sends a NEXT signal to the producer, requesting the next piece of data.
    • close(port, error?): Sends a CLOSE signal to the producer. If an error is provided, it is passed along to signal a failure.
    import { open, next, close } from "@nact/streams";
    
    // To start a stream
    open(producerPort, consumerActor);
    
    // To request the next item
    next(producerPort);
    
    // To terminate the stream
    close(producerPort, someError);
  10. Configure actor supervision with SupervisionActions and defaultSupervisionPolicy

    next
    Nact uses supervision policies to handle actor failures. You can use SupervisionActions to define how a supervisor should react to an actor's failure and defaultSupervisionPolicy as a starting point for custom policies.
  11. Use PersistentActorContext and PersistentActorProps types

    next

    When implementing or extending persistent actors, you can use the following types from @nact/persistence:

    • PersistentActorContext: Represents the context available within a persistent actor's lifecycle.
    • PersistentActorProps: Defines the properties/configuration passed during the spawning of a persistent actor.