Skip to content

Commit 9f564a4

Browse files
committed
Update docs
1 parent d72f974 commit 9f564a4

File tree

1 file changed

+140
-34
lines changed

1 file changed

+140
-34
lines changed

README.md

Lines changed: 140 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ We're also going to configure a few things for our application build to work, in
113113
<dependency>
114114
<groupId>com.github.eigr</groupId>
115115
<artifactId>spawn-java-std-sdk</artifactId>
116-
<version>v0.1.6</version>
116+
<version>v0.2.5</version>
117117
</dependency>
118118
<dependency>
119119
<groupId>ch.qos.logback</groupId>
@@ -215,7 +215,7 @@ touch src/main/proto/domain/domain.proto
215215

216216
And let's populate this file with the following content:
217217

218-
```proto
218+
```protobuf
219219
syntax = "proto3";
220220
221221
package domain;
@@ -389,17 +389,49 @@ For example, named actors are instantiated the first time as soon as the host ap
389389

390390
Actors in Spawn can subscribe to a thread and receive, as well as broadcast, events for a given thread.
391391

392-
To consume from a topic, you just need to configure the Actor decorator using the channel option as follows:
392+
To consume from a topic, you just need to configure the Actor annotation using the channel option as follows:
393393

394394
```Java
395-
395+
@NamedActor(name = "joe", stateful = true, stateType = Domain.JoeState.class, channel = "test")
396396
```
397397
In the case above, the Actor `joe` was configured to receive events that are forwarded to the topic called `test`.
398398

399399
To produce events in a topic, just use the Broadcast Workflow. The example below demonstrates a complete example of producing and consuming events. In this case, the same actor is the event consumer and producer, but in a more realistic scenario, different actors would be involved in these processes.
400400

401401
```Java
402+
package io.eigr.spawn.java.demo;
403+
404+
import io.eigr.spawn.api.workflows.Broadcast;
405+
// some imports omitted for brevity
406+
407+
@NamedActor(name = "joe", stateful = true, stateType = Domain.JoeState.class, channel = "test")
408+
public class Joe {
409+
@TimerAction(name = "hi", period = 60000)
410+
public Value hi(ActorContext<Domain.JoeState> context) {
411+
Domain.Request msg = Domain.Request.newBuilder()
412+
.setLanguage("erlang")
413+
.build();
414+
415+
return Value.at()
416+
.flow(Broadcast.to("test", "setLanguage", msg))
417+
.response(Domain.Reply.newBuilder()
418+
.setResponse("Hello From Erlang")
419+
.build())
420+
.state(updateState("erlang"))
421+
.reply();
422+
}
402423

424+
@Action(inputType = Domain.Request.class)
425+
public Value setLanguage(Domain.Request msg, ActorContext<Domain.JoeState> context) {
426+
return Value.at()
427+
.response(Domain.Reply.newBuilder()
428+
.setResponse("Hello From Java")
429+
.build())
430+
.state(updateState("java"))
431+
.reply();
432+
}
433+
// ....
434+
}
403435
```
404436

405437
### Side Effects
@@ -426,7 +458,9 @@ See an example:
426458

427459
### Pipe
428460

429-
Similarly, sometimes we want to chain a request through several processes. For example forwarding an actor's computational output as another actor's input. There is this type of routing we call Pipe, as the name suggests, a pipe forwards what would be the response of the received request to the input of another Action in another Actor.
461+
Similarly, sometimes we want to chain a request through several processes. For example forwarding an actor's computational
462+
output as another actor's input. There is this type of routing we call Pipe, as the name suggests, a pipe forwards what
463+
would be the response of the received request to the input of another Action in another Actor.
430464
In the end, just like in a Forward, it is the response of the last Actor in the chain of routing to the original caller.
431465

432466
Example:
@@ -439,11 +473,18 @@ Forwards and pipes do not have an upper thread limit other than the request time
439473

440474
### State Management
441475

442-
The Spawn runtime handles the internal state of your actors. It is he who maintains its state based on the types of actors and configurations that you, the developer, have made.
476+
The Spawn runtime handles the internal state of your actors. It is he who maintains its state based on the types of actors
477+
and configurations that you, the developer, have made.
443478

444-
The persistence of the state of the actors happens through snapshots that follow to [Write Behind Pattern](https://redisson.org/glossary/write-through-and-write-behind-caching.html) during the period in which the Actor is active and [Write Ahead](https://martinfowler.com/articles/patterns-of-distributed-systems/wal.html) during the moment of the Actor's deactivation. That is, data is saved at regular intervals asynchronously while the Actor is active and once synchronously when the Actor suffers a deactivation, when it is turned off.
479+
The persistence of the state of the actors happens through snapshots that follow to [Write Behind Pattern](https://redisson.org/glossary/write-through-and-write-behind-caching.html)
480+
during the period in which the Actor is active and [Write Ahead](https://martinfowler.com/articles/patterns-of-distributed-systems/wal.html)
481+
during the moment of the Actor's deactivation.
482+
That is, data is saved at regular intervals asynchronously while the Actor is active and once synchronously
483+
when the Actor suffers a deactivation, when it is turned off.
445484

446-
These snapshots happen from time to time. And this time is configurable through the ***snapshot_timeout*** property of the ***ActorSettings*** class. However, you can tell the Spawn runtime that you want it to persist the data immediately synchronously after executing an Action. And this can be done in the following way:
485+
These snapshots happen from time to time. And this time is configurable through the ***snapshot_timeout*** property of the ***ActorSettings*** class.
486+
However, you can tell the Spawn runtime that you want it to persist the data immediately synchronously after executing an Action.
487+
And this can be done in the following way:
447488

448489
Example:
449490

@@ -458,19 +499,25 @@ The most important thing in this example is the use of the parameter checkpoint=
458499
```
459500

460501
It is this parameter that will indicate to the Spawn runtime that you want the data to be saved immediately after this Action is called back.
461-
In most cases this strategy is completely unnecessary, as the default strategy is sufficient for most use cases. But Spawn democratically lets you choose when you want your data persisted.
502+
In most cases this strategy is completely unnecessary, as the default strategy is sufficient for most use cases.
503+
But Spawn democratically lets you choose when you want your data persisted.
462504

463-
In addition to this functionality regarding state management, Spawn also allows you to perform some more operations on your Actors such as restoring the actor's state to a specific point in time:
505+
In addition to this functionality regarding state management, Spawn also allows you to perform some more operations
506+
on your Actors such as restoring the actor's state to a specific point in time:
464507

465508
Restore Example:
466509

467510
TODO
468511

469512
## Using Actors
470513

471-
There are several ways to interact with our actors, some internal to the application code and others external to the application code. In this section we will deal with the internal ways of interacting with our actors and this will be done through direct calls to them. For more details on the external ways to interact with your actors see the [Activators](#activators) section.
514+
There are several ways to interact with our actors, some internal to the application code and others external to the application code.
515+
In this section we will deal with the internal ways of interacting with our actors and this will be done through direct calls to them.
516+
For more details on the external ways to interact with your actors see the [Activators](#activators) section.
472517

473-
In order to be able to call methods of an Actor, we first need to get a reference to the actor. This is done with the help of the static method `create_actor_ref` of the `Spawn` class. This method accepts some arguments, the most important being `system`, `actor_name` and `parent`.
518+
In order to be able to call methods of an Actor, we first need to get a reference to the actor. This is done with the
519+
help of the static method `create_actor_ref` of the `Spawn` class. This method accepts some arguments,
520+
the most important being `system`, `actor_name` and `parent`.
474521

475522
In the sections below we will give some examples of how to invoke different types of actors in different ways.
476523

@@ -479,38 +526,82 @@ In the sections below we will give some examples of how to invoke different type
479526
To invoke an actor named like the one we defined in section [Getting Started](#getting-started) we could do as follows:
480527

481528
```Java
482-
529+
ActorRef joeActor = spawnSystem.createActorRef("spawn-system", "joe");
530+
531+
Domain.Request msg = Domain.Request.newBuilder()
532+
.setLanguage("erlang")
533+
.build();
534+
Domain.Reply reply =
535+
(Domain.Reply) joeActor.invoke("setLanguage", msg, Domain.Reply.class, Optional.empty());
483536
```
484537

485-
Calls like the one above, that is, synchronous calls, always returned a tuple composed of the invocation status message and the response object emitted by the Actor.
486-
487-
### Call Unnamed Actors
538+
More detailed in complete main class:
488539

489-
Unnamed actors are equally simple to invoke. All that is needed is to inform the `parent` parameter which refers to the name given to the actor that defines the ActorRef template.
540+
```java
541+
package io.eigr.spawn.java.demo;
490542

491-
To better exemplify, let's first show the Actor's definition code and later how we would call this actor with a concrete name at runtime:
543+
import io.eigr.spawn.Spawn;
544+
import io.eigr.spawn.Spawn.SpawnSystem;
545+
import io.eigr.spawn.api.actors.ActorRef;
546+
import io.eigr.spawn.java.demo.domain.Domain;
492547

493-
```Java
548+
import java.util.Optional;
494549

495-
```
550+
public class App {
551+
public static void main(String[] args) throws Exception {
552+
Spawn spawnSystem = new SpawnSystem()
553+
.create("spawn-system")
554+
.withPort(8091)
555+
.withProxyPort(9003)
556+
.withActor(Joe.class)
557+
.build();
496558

497-
The important part of the code above is the following snippet:
559+
spawnSystem.start();
498560

499-
```Java
561+
ActorRef joeActor = spawnSystem.createActorRef("spawn-system", "joe");
500562

563+
Domain.Request msg = Domain.Request.newBuilder()
564+
.setLanguage("erlang")
565+
.build();
566+
Domain.Reply reply =
567+
(Domain.Reply) joeActor.invoke("setLanguage", msg, Domain.Reply.class, Optional.empty());
568+
}
569+
}
501570
```
502571

503-
These tells Spawn that this actor will actually be named at runtime. The name parameter in this case is just a reference that will be used later so that we can actually create an instance of the real Actor.
572+
### Call Unnamed Actors
573+
574+
Unnamed actors are equally simple to invoke. All that is needed is to inform the `parent` parameter which refers to the
575+
name given to the actor that defines the ActorRef template.
504576

505-
Finally, below we will see how to invoke such an actor. We'll name the royal actor "mike":
577+
To better exemplify, let's first show the Actor's definition code and later how we would call this actor with a concrete
578+
name at runtime:
506579

507580
```Java
581+
ActorRef mike = spawnSystem.createActorRef("spawn-system", "mike", "abs_actor");
582+
583+
Domain.Request msg = Domain.Request.newBuilder()
584+
.setLanguage("erlang")
585+
.build();
586+
Domain.Reply reply =
587+
(Domain.Reply) mike.invoke("setLanguage", msg, Domain.Reply.class, Optional.empty());
588+
```
589+
590+
The important part of the code above is the following snippet:
508591

592+
```Java
593+
ActorRef mike = spawnSystem.createActorRef("spawn-system", "mike", "abs_actor");
509594
```
510595

596+
These tells Spawn that this actor will actually be named at runtime. The name parameter in this case is just a reference
597+
that will be used later so that we can actually create an instance of the real Actor.
598+
511599
### Async calls and other options
512600

513-
Basically Spawn can perform actor functions in two ways. Synchronously, where the callee waits for a response, or asynchronously, where the callee doesn't care about the return value of the call. In this context we should not confuse Spawn's asynchronous way with Java's concept of async because async for Spawn is just a fire-and-forget call.
601+
Basically Spawn can perform actor functions in two ways. Synchronously, where the callee waits for a response,
602+
or asynchronously, where the callee doesn't care about the return value of the call.
603+
In this context we should not confuse Spawn's asynchronous way with Java's concept of async because async for Spawn is
604+
just a fire-and-forget call.
514605

515606
Therefore, to call an actor's function asynchronously, just inform the parameter async_mode with the value True:
516607

@@ -520,21 +611,25 @@ Therefore, to call an actor's function asynchronously, just inform the parameter
520611

521612
## Deploy
522613

523-
See [Getting Started](https://github.com/eigr/spawn#getting-started) section from the main Spawn repository for more details on how to deploy a Spawn application.
614+
See [Getting Started](https://github.com/eigr/spawn#getting-started) section from the main Spawn repository for more
615+
details on how to deploy a Spawn application.
524616

525617
### Packing with Containers
526618

527619
Spawn is a k8s based runtime and therefore your workloads should be made up of containers.
528620

529-
So all you need to do is create a container with your Java application. There are several tutorials on the internet that can help you with this process and we will not go into detail in this document.
621+
So all you need to do is create a container with your Java application. There are several tutorials on the internet that
622+
can help you with this process and we will not go into detail in this document.
530623

531624
### Defining an ActorSytem
532625

533-
See [Getting Started](https://github.com/eigr/spawn#getting-started) section from the main Spawn repository for more details on how to define an ActorSystem.
626+
See [Getting Started](https://github.com/eigr/spawn#getting-started) section from the main Spawn repository for more
627+
details on how to define an ActorSystem.
534628

535629
### Defining an ActorHost
536630

537-
See [Getting Started](https://github.com/eigr/spawn#getting-started) section from the main Spawn repository for more details on how to define an ActorHost.
631+
See [Getting Started](https://github.com/eigr/spawn#getting-started) section from the main Spawn repository for more
632+
details on how to define an ActorHost.
538633

539634
### Activators
540635
TODO
@@ -543,13 +638,19 @@ TODO
543638

544639
According to Wikipedia Actor Model is:
545640

546-
"A mathematical model of concurrent computation that treats actor as the universal primitive of concurrent computation. In response to a message it receives, an actor can: make local decisions, create more actors, send more messages, and determine how to respond to the next message received. Actors may modify their own private state, but can only affect each other indirectly through messaging (removing the need for lock-based synchronization).
641+
"A mathematical model of concurrent computation that treats actor as the universal primitive of concurrent computation.
642+
In response to a message it receives, an actor can: make local decisions, create more actors, send more messages,
643+
and determine how to respond to the next message received. Actors may modify their own private state, but can only affect
644+
each other indirectly through messaging (removing the need for lock-based synchronization).
547645

548-
The actor model originated in 1973. It has been used both as a framework for a theoretical understanding of computation and as the theoretical basis for several practical implementations of concurrent systems."
646+
The actor model originated in 1973. It has been used both as a framework for a theoretical understanding of computation
647+
and as the theoretical basis for several practical implementations of concurrent systems."
549648

550649
The Actor Model was proposed by Carl Hewitt, Peter Bishop, and Richard Steiger and is inspired by several characteristics of the physical world.
551650

552-
Although it emerged in the 70s of the last century, only in the previous two decades of our century has this model gained strength in the software engineering communities due to the massive amount of existing data and the performance and distribution requirements of the most current applications.
651+
Although it emerged in the 70s of the last century, only in the previous two decades of our century has this model
652+
gained strength in the software engineering communities due to the massive amount of existing data and the performance
653+
and distribution requirements of the most current applications.
553654

554655
For more information about the Actor Model, see the following links:
555656

@@ -563,10 +664,15 @@ https://doc.akka.io/docs/akka/current/general/actors.html
563664

564665
### Virtual Actors
565666

566-
In the context of the Virtual Actor paradigm, actors possess the inherent ability to seamlessly retain their state. The underlying framework dynamically manages the allocation of actors to specific nodes. If a node happens to experience an outage, the framework automatically revives the affected actor on an alternate node. This process of revival maintains data integrity as actors are inherently designed to preserve their state. Interruptions to availability are minimized during this seamless transition, contingent on the actors correctly implementing their state preservation mechanisms.
667+
In the context of the Virtual Actor paradigm, actors possess the inherent ability to seamlessly retain their state.
668+
The underlying framework dynamically manages the allocation of actors to specific nodes. If a node happens to experience an outage,
669+
the framework automatically revives the affected actor on an alternate node. This process of revival maintains
670+
data integrity as actors are inherently designed to preserve their state. Interruptions to availability are minimized
671+
during this seamless transition, contingent on the actors correctly implementing their state preservation mechanisms.
567672

568673
The Virtual Actor model offers several merits:
569674

570675
* **Scalability**: The system can effortlessly accommodate a higher number of actor instances by introducing additional nodes.
571676

572-
* **Availability**: In case of a node failure, actors swiftly and nearly instantly regenerate on another node, all while safeguarding their state from loss.
677+
* **Availability**: In case of a node failure, actors swiftly and nearly instantly regenerate on another node,
678+
all while safeguarding their state from loss.

0 commit comments

Comments
 (0)