@@ -7,6 +7,8 @@ JVM User Language Support for [Spawn](https://github.com/eigr/spawn).
772 . [ Getting Started] ( #getting-started )
883 . [ Advanced Use Cases] ( #advanced-use-cases )
99 - [ Types of Actors] ( #types-of-actors )
10+ - [ Stateless Actors] ( #stateless-actors )
11+ - [ Considerations about Spawn actors] ( #considerations-about-spawn-actors )
1012 - [ Broadcast] ( #broadcast )
1113 - [ Side Effects] ( #side-effects )
1214 - [ Forward] ( #forward )
@@ -90,7 +92,7 @@ The second thing we have to do is add the spawn dependency to the project.
9092<dependency >
9193 <groupId >com.github.eigr</groupId >
9294 <artifactId >spawn-java-std-sdk</artifactId >
93- <version >v0.4.1 </version >
95+ <version >v0.5.0 </version >
9496</dependency >
9597```
9698We're also going to configure a few things for our application build to work, including compiling the protobuf files.
@@ -124,7 +126,7 @@ See below a full example of the pom.xml file:
124126 <dependency >
125127 <groupId >com.github.eigr</groupId >
126128 <artifactId >spawn-java-std-sdk</artifactId >
127- <version >v0.4.1 </version >
129+ <version >v0.5.0 </version >
128130 </dependency >
129131 <dependency >
130132 <groupId >ch.qos.logback</groupId >
@@ -286,12 +288,12 @@ package io.eigr.spawn.java.demo;
286288import io.eigr.spawn.api.Value ;
287289import io.eigr.spawn.api.actors.ActorContext ;
288290import io.eigr.spawn.api.actors.annotations.Action ;
289- import io.eigr.spawn.api.actors.annotations.NamedActor ;
291+ import io.eigr.spawn.api.actors.annotations.stateful.StatefulNamedActor ;
290292import io.eigr.spawn.java.demo.domain.Domain ;
291293import org.slf4j.Logger ;
292294import org.slf4j.LoggerFactory ;
293295
294- @NamedActor (name = " joe" , stateType = Domain . JoeState . class)
296+ @StatefulNamedActor (name = " joe" , stateType = Domain . JoeState . class)
295297public class Joe {
296298 private static final Logger log = LoggerFactory . getLogger(Joe . class);
297299
@@ -408,12 +410,12 @@ package io.eigr.spawn.java.demo;
408410import io.eigr.spawn.api.Value ;
409411import io.eigr.spawn.api.actors.ActorContext ;
410412import io.eigr.spawn.api.actors.annotations.Action ;
411- import io.eigr.spawn.api.actors.annotations.NamedActor ;
413+ import io.eigr.spawn.api.actors.annotations.stateful.StatefulNamedActor ;
412414import io.eigr.spawn.java.demo.domain.Domain ;
413415
414416import java.util.Map ;
415417
416- @NamedActor (name = " joe" , stateful = true , stateType = Domain . JoeState . class, channel = " test" )
418+ @StatefulNamedActor (name = " joe" , stateful = true , stateType = Domain . JoeState . class, channel = " test" )
417419public final class Joe {
418420 private final String someValue;
419421
@@ -509,6 +511,37 @@ during program execution. Otherwise, they behave like named actors.
509511assigned to them at compile time. Pooled actors are generally used when higher performance is needed and are also
510512recommended for handling serverless loads.
511513
514+ ### Stateless Actors
515+
516+ In addition to these types, Spawn also allows the developer to choose Stateful actors, who need to maintain the state, or Stateless, those who do not need to maintain the state.
517+ For this the developer just needs to make use of the correct annotation. For example I could declare a Serverless Actor using the following code:
518+
519+ ``` java
520+ package io.eigr.spawn.test.actors ;
521+
522+ import io.eigr.spawn.api.Value ;
523+ import io.eigr.spawn.api.actors.ActorContext ;
524+ import io.eigr.spawn.api.actors.annotations.Action ;
525+ import io.eigr.spawn.api.actors.annotations.stateless.StatelessNamedActor ;
526+ import io.eigr.spawn.java.test.domain.Actor ;
527+
528+ @StatelessNamedActor (name = " test_joe" , channel = " test.channel" )
529+ public class JoeActor {
530+ @Action
531+ public Value hi (Actor .Request msg , ActorContext<?> context ) {
532+ return Value . at()
533+ .response(Actor . Reply . newBuilder()
534+ .setResponse(" Hello From Java" )
535+ .build())
536+ .reply();
537+ }
538+ }
539+ ```
540+
541+ Other than that the same Named, UnNamed types are supported. Just use the StatelessNamed or StatelessUnNamed annotations.
542+
543+ ### Considerations about Spawn actors
544+
512545Another important feature of Spawn Actors is that the lifecycle of each Actor is managed by the platform itself.
513546This means that an Actor will exist when it is invoked and that it will be deactivated after an idle time in its execution.
514547This pattern is known as [ Virtual Actors] ( #virtual-actors ) but Spawn's implementation differs from some other known
@@ -526,7 +559,7 @@ Actors in Spawn can subscribe to a thread and receive, as well as broadcast, eve
526559To consume from a topic, you just need to configure the Actor annotation using the channel option as follows:
527560
528561``` Java
529- @NamedActor (name = " joe" , stateful = true , stateType = Domain . JoeState . class, channel = " test" )
562+ @StatefulNamedActor (name = " joe" , stateful = true , stateType = Domain . JoeState . class, channel = " test" )
530563```
531564In the case above, the Actor ` joe ` was configured to receive events that are forwarded to the topic called ` test ` .
532565
@@ -540,7 +573,7 @@ package io.eigr.spawn.java.demo;
540573import io.eigr.spawn.api.actors.workflows.Broadcast ;
541574// some imports omitted for brevity
542575
543- @NamedActor (name = " joe" , stateful = true , stateType = Domain . JoeState . class, channel = " test" )
576+ @StatefulNamedActor (name = " joe" , stateType = Domain . JoeState . class, channel = " test" )
544577public class Joe {
545578 @TimerAction (name = " hi" , period = 60000 )
546579 public Value hi (ActorContext<Domain . JoeState > context ) {
@@ -582,11 +615,11 @@ import io.eigr.spawn.api.Value;
582615import io.eigr.spawn.api.actors.ActorContext ;
583616import io.eigr.spawn.api.actors.ActorRef ;
584617import io.eigr.spawn.api.actors.annotations.Action ;
585- import io.eigr.spawn.api.actors.annotations.NamedActor ;
618+ import io.eigr.spawn.api.actors.annotations.stateful.StatefulNamedActor ;
586619import io.eigr.spawn.api.actors.workflows.SideEffect ;
587620import io.eigr.spawn.java.demo.domain.Domain ;
588621
589- @NamedActor (name = " side_effect_actor" , stateful = true , stateType = Domain . State . class)
622+ @StatefulNamedActor (name = " side_effect_actor" , stateful = true , stateType = Domain . State . class)
590623public class SideEffectActorExample {
591624 @Action
592625 public Value setLanguage (Domain .Request msg , ActorContext<Domain . State > ctx ) throws Exception {
@@ -628,13 +661,13 @@ import io.eigr.spawn.api.Value;
628661import io.eigr.spawn.api.actors.ActorContext ;
629662import io.eigr.spawn.api.actors.ActorRef ;
630663import io.eigr.spawn.api.actors.annotations.Action ;
631- import io.eigr.spawn.api.actors.annotations.NamedActor ;
664+ import io.eigr.spawn.api.actors.annotations.stateful.StatefulNamedActor ;
632665import io.eigr.spawn.api.actors.workflows.Forward ;
633666import io.eigr.spawn.java.demo.domain.Domain ;
634667import org.slf4j.Logger ;
635668import org.slf4j.LoggerFactory ;
636669
637- @NamedActor (name = " routing_actor" , stateful = true , stateType = Domain . State . class)
670+ @StatefulNamedActor (name = " routing_actor" , stateful = true , stateType = Domain . State . class)
638671public class ForwardExample {
639672 private static final Logger log = LoggerFactory . getLogger(ForwardExample . class);
640673
@@ -670,11 +703,11 @@ import io.eigr.spawn.api.Value;
670703import io.eigr.spawn.api.actors.ActorContext ;
671704import io.eigr.spawn.api.actors.ActorRef ;
672705import io.eigr.spawn.api.actors.annotations.Action ;
673- import io.eigr.spawn.api.actors.annotations.NamedActor ;
706+ import io.eigr.spawn.api.actors.annotations.stateful.StatefulNamedActor ;
674707import io.eigr.spawn.api.actors.workflows.Pipe ;
675708import io.eigr.spawn.java.demo.domain.Domain ;
676709
677- @NamedActor (name = " pipe_actor" , stateful = true , stateType = Domain . State . class)
710+ @StatefulNamedActor (name = " pipe_actor" , stateful = true , stateType = Domain . State . class)
678711public class PipeActorExample {
679712
680713 @Action
@@ -713,7 +746,7 @@ That is, data is saved at regular intervals asynchronously while the Actor is ac
713746when the Actor suffers a deactivation, when it is turned off.
714747
715748These snapshots happen from time to time. And this time is configurable through the *** snapshotTimeout*** property of
716- the *** NamedActor *** or *** UnNamedActor *** annotation.
749+ the *** StatefulNamedActor *** or *** UnStatefulNamedActor *** annotation.
717750However, you can tell the Spawn runtime that you want it to persist the data immediately synchronously after executing an Action.
718751And this can be done in the following way:
719752
@@ -723,10 +756,10 @@ Example:
723756import io.eigr.spawn.api.Value ;
724757import io.eigr.spawn.api.actors.ActorContext ;
725758import io.eigr.spawn.api.actors.annotations.Action ;
726- import io.eigr.spawn.api.actors.annotations.NamedActor ;
759+ import io.eigr.spawn.api.actors.annotations.stateful.StatefulNamedActor ;
727760import io.eigr.spawn.java.demo.domain.Domain ;
728761
729- @NamedActor (name = " joe" , stateful = true , stateType = Domain . JoeState . class)
762+ @StatefulNamedActor (name = " joe" , stateType = Domain . JoeState . class)
730763public final class Joe {
731764 @Action (inputType = Domain . Request . class)
732765 public Value setLanguage (Domain .Request msg , ActorContext<Domain . JoeState > context ) {
@@ -743,8 +776,8 @@ public final class Joe {
743776
744777The most important thing in this example is the use of the last parameter with the true value:
745778
746- ``` Java
747- . state(updateState(" java" ), true )
779+ ```
780+ state(updateState("java"), true)
748781```
749782
750783It is this parameter that will indicate to the Spawn runtime that you want the data to be saved immediately after this
@@ -781,7 +814,7 @@ ActorRef joeActor = spawnSystem.createActorRef("spawn-system", "joe");
781814 .setLanguage(" erlang" )
782815 .build();
783816 Domain . Reply reply =
784- (Domain . Reply ) joeActor. invoke(" setLanguage" , msg, Domain . Reply . class, Optional . empty() );
817+ (Domain . Reply ) joeActor. invoke(" setLanguage" , msg, Domain . Reply . class);
785818```
786819
787820More detailed in complete main class:
@@ -813,7 +846,7 @@ public class App {
813846 .setLanguage(" erlang" )
814847 .build();
815848 Domain . Reply reply =
816- (Domain . Reply ) joeActor. invoke(" setLanguage" , msg, Domain . Reply . class, Optional . empty() );
849+ (Domain . Reply ) joeActor. invoke(" setLanguage" , msg, Domain . Reply . class);
817850 }
818851}
819852```
@@ -830,7 +863,7 @@ name at runtime:
830863package io.eigr.spawn.java.demo ;
831864// omitted imports for brevity...
832865
833- @UnNamedActor (name = " abs_actor" , stateful = true , stateType = Domain . State . class)
866+ @UnStatefulNamedActor (name = " abs_actor" , stateful = true , stateType = Domain . State . class)
834867public class AbstractActor {
835868 @Action (inputType = Domain . Request . class)
836869 public Value setLanguage (Domain .Request msg , ActorContext<Domain . State > context ) {
@@ -859,7 +892,7 @@ ActorRef mike = spawnSystem.createActorRef("spawn-system", "mike", "abs_actor");
859892 .setLanguage(" erlang" )
860893 .build();
861894 Domain . Reply reply =
862- (Domain . Reply ) mike. invoke(" setLanguage" , msg, Domain . Reply . class, Optional . empty() );
895+ (Domain . Reply ) mike. invoke(" setLanguage" , msg, Domain . Reply . class);
863896```
864897
865898The important part of the code above is the following snippet:
@@ -879,11 +912,10 @@ or asynchronously, where the callee doesn't care about the return value of the c
879912In this context we should not confuse Spawn's asynchronous way with Java's concept of async like Promises because async for Spawn is
880913just a fire-and-forget call.
881914
882- Therefore, to call an actor's function asynchronously, just inform the parameter async using the InvocationOpts class with the value true :
915+ Therefore, to call an actor's function asynchronously, just use the invokeAsync method :
883916
884917``` Java
885- InvocationOpts opts = InvocationOpts . builder(). async(true ). build();
886- mike. invoke(" setLanguage" , msg, Domain . Reply . class, opts);
918+ mike. invokeAsync(" setLanguage" , msg, Domain . Reply . class);
887919```
888920
889921## Deploy
0 commit comments