Skip to content

Commit 8182009

Browse files
committed
New API
1 parent e76dac2 commit 8182009

File tree

5 files changed

+148
-98
lines changed

5 files changed

+148
-98
lines changed

README.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,6 @@ public class App {
332332
public static void main(String[] args) throws Exception {
333333
Spawn spawnSystem = new SpawnSystem()
334334
.create("spawn-system")
335-
.withPort(8091)
336-
.withProxyPort(9003)
337335
.addActor(Joe.class)
338336
.build();
339337

@@ -342,6 +340,34 @@ public class App {
342340
}
343341
```
344342

343+
Or passing transport options like:
344+
345+
```Java
346+
package io.eigr.spawn.java.demo;
347+
348+
import io.eigr.spawn.api.Spawn;
349+
import io.eigr.spawn.api.transport.TransportOpts;
350+
351+
public class App {
352+
public static void main(String[] args) throws Exception {
353+
TransportOpts opts = TransportOpts.builder()
354+
.executor()
355+
.port(8091)
356+
.proxyPort(9003)
357+
.executor(Executors.newVirtualThreadPerTaskExecutor()) // If you use java above 19 and use the --enable-preview flag when running the jvm
358+
.build();
359+
360+
Spawn spawnSystem = new SpawnSystem()
361+
.create("spawn-system")
362+
.addActor(Joe.class)
363+
.withTransportOpts(opts)
364+
.build();
365+
366+
spawnSystem.start();
367+
}
368+
}
369+
```
370+
345371
Then:
346372

347373
```shell

src/main/java/io/eigr/spawn/api/Spawn.java

Lines changed: 23 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import io.eigr.spawn.api.actors.annotations.stateless.StatelessNamedActor;
1212
import io.eigr.spawn.api.actors.annotations.stateless.StatelessPooledActor;
1313
import io.eigr.spawn.api.actors.annotations.stateless.StatelessUnNamedActor;
14+
import io.eigr.spawn.api.transport.TransportOpts;
1415
import io.eigr.spawn.internal.Entity;
1516
import io.eigr.spawn.internal.client.OkHttpSpawnClient;
1617
import io.eigr.spawn.internal.client.SpawnClient;
@@ -22,7 +23,6 @@
2223
import java.net.InetSocketAddress;
2324
import java.util.*;
2425
import java.util.concurrent.Executor;
25-
import java.util.concurrent.Executors;
2626
import java.util.function.Function;
2727
import java.util.stream.Collectors;
2828

@@ -41,18 +41,17 @@ public final class Spawn {
4141
private final String system;
4242
private final List<Entity> entities;
4343
private String host;
44-
private Optional<Executor> optionalExecutor;
45-
44+
private Executor executor;
4645

4746
private Spawn(SpawnSystem builder) {
4847
this.system = builder.system;
4948
this.entities = builder.entities;
50-
this.port = builder.port;
51-
this.host = builder.host;
52-
this.proxyHost = builder.proxyHost;
53-
this.proxyPort = builder.proxyPort;
49+
this.port = builder.transportOpts.getPort();
50+
this.host = builder.transportOpts.getHost();
51+
this.proxyHost = builder.transportOpts.getProxyHost();
52+
this.proxyPort = builder.transportOpts.getProxyPort();
5453
this.client = builder.client;
55-
this.optionalExecutor = builder.optionalExecutor;
54+
this.executor = builder.transportOpts.getExecutor();
5655
}
5756

5857
public int getPort() {
@@ -87,11 +86,7 @@ public void start() throws Exception {
8786
private void startServer() throws IOException {
8887
HttpServer httpServer = HttpServer.create(new InetSocketAddress(this.host, this.port), 0);
8988
httpServer.createContext(HTTP_ACTORS_ACTIONS_URI, new ActorServiceHandler(this, this.entities));
90-
if (this.optionalExecutor.isPresent()) {
91-
httpServer.setExecutor(this.optionalExecutor.get());
92-
} else {
93-
httpServer.setExecutor(Executors.newCachedThreadPool());
94-
}
89+
httpServer.setExecutor(this.executor);
9590
httpServer.start();
9691
}
9792

@@ -228,41 +223,19 @@ public static final class SpawnSystem {
228223

229224
private final List<Entity> entities = new ArrayList<>();
230225
private SpawnClient client;
231-
private int port = 8091;
232-
private String host = "127.0.0.1";
233-
private String proxyHost = "127.0.0.1";
234-
private int proxyPort = 9001;
235226
private String system = "spawn-system";
236227

237-
private Optional<Executor> optionalExecutor = Optional.empty();
228+
private TransportOpts transportOpts = TransportOpts.builder().build();
238229

239230
public SpawnSystem create(String system) {
240231
this.system = system;
241232
return this;
242233
}
243234

244-
public SpawnSystem withPort(int port) {
245-
this.port = port;
246-
return this;
247-
}
248-
249-
public SpawnSystem withHost(String host) {
250-
this.host = host;
251-
return this;
252-
}
253-
254-
public SpawnSystem withProxyHost(String host) {
255-
this.proxyHost = host;
256-
return this;
257-
}
258-
259-
public SpawnSystem withProxyPort(int port) {
260-
this.proxyPort = port;
261-
return this;
262-
}
263-
264-
public SpawnSystem withHttpHandlerExecutor(Executor executor) {
265-
this.optionalExecutor = Optional.of(executor);
235+
public SpawnSystem createFromEnv() {
236+
String system = System.getenv("PROXY_ACTOR_SYSTEM_NAME");
237+
Objects.requireNonNull(system, "To use createFromEnv it is necessary to have defined the environment variable PROXY_ACTOR_SYSTEM_NAME");
238+
this.system = system;
266239
return this;
267240
}
268241

@@ -282,8 +255,17 @@ public SpawnSystem addActorWithArgs(Class<?> actorKlass, Object arg, ActorFactor
282255
return this;
283256
}
284257

258+
public SpawnSystem withTransportOpts(TransportOpts opts) {
259+
this.transportOpts = opts;
260+
return this;
261+
}
262+
285263
public Spawn build() {
286-
this.client = new OkHttpSpawnClient(this.system, this.proxyHost, this.proxyPort);
264+
this.client = new OkHttpSpawnClient(
265+
this.system,
266+
this.transportOpts.getProxyHost(),
267+
this.transportOpts.getProxyPort());
268+
287269
return new Spawn(this);
288270
}
289271

src/main/java/io/eigr/spawn/api/actors/ActorRef.java

Lines changed: 64 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.eigr.spawn.api.actors;
22

3+
import com.github.benmanes.caffeine.cache.Cache;
4+
import com.github.benmanes.caffeine.cache.Caffeine;
35
import com.google.protobuf.Any;
46
import com.google.protobuf.Empty;
57
import com.google.protobuf.GeneratedMessageV3;
@@ -10,48 +12,50 @@
1012
import io.eigr.spawn.api.exceptions.ActorNotFoundException;
1113
import io.eigr.spawn.internal.client.SpawnClient;
1214

15+
import java.time.Duration;
16+
import java.util.Objects;
1317
import java.util.Optional;
1418

1519
public final class ActorRef {
20+
private static final int CACHE_MAXIMUM_SIZE = 1_000;
21+
private static final int CACHE_EXPIRE_AFTER_WRITE_SECONDS = 60;
22+
private static final Cache<ActorOuterClass.ActorId, ActorRef> ACTOR_REF_CACHE = Caffeine.newBuilder()
23+
.maximumSize(CACHE_MAXIMUM_SIZE)
24+
.expireAfterWrite(Duration.ofSeconds(CACHE_EXPIRE_AFTER_WRITE_SECONDS))
25+
.build();
1626

1727
private final ActorOuterClass.ActorId actorId;
1828

19-
private final String name;
20-
21-
private final String system;
22-
23-
private final Optional<String> parent;
24-
2529
private final SpawnClient client;
2630

27-
private ActorRef(SpawnClient client, String system, String name) throws Exception {
31+
private ActorRef(ActorOuterClass.ActorId actorId, SpawnClient client) {
2832
this.client = client;
29-
this.system = system;
30-
this.name = name;
31-
this.parent = Optional.empty();
32-
this.actorId = buildActorId();
33-
if (this.parent.isPresent()){
34-
spawnActor();
35-
}
36-
}
37-
38-
private ActorRef(SpawnClient client, String system, String name, String parent) throws Exception {
39-
this.client = client;
40-
this.system = system;
41-
this.name = name;
42-
this.parent = Optional.of(parent);
43-
this.actorId = buildActorId();
44-
if (this.parent.isPresent()){
45-
spawnActor();
46-
}
33+
this.actorId = actorId;
4734
}
4835

4936
public static ActorRef of(SpawnClient client, String system, String name) throws Exception {
50-
return new ActorRef(client, system, name);
37+
ActorOuterClass.ActorId actorId = buildActorId(system, name);
38+
ActorRef ref = ACTOR_REF_CACHE.getIfPresent(actorId);
39+
if (Objects.nonNull(ref)){
40+
return ref;
41+
}
42+
43+
ref = new ActorRef(actorId, client);
44+
ACTOR_REF_CACHE.put(actorId, ref);
45+
return ref;
5146
}
5247

5348
public static ActorRef of(SpawnClient client, String system, String name, String parent) throws Exception {
54-
return new ActorRef(client, system, name, parent);
49+
ActorOuterClass.ActorId actorId = buildActorId(system, name, parent);
50+
ActorRef ref = ACTOR_REF_CACHE.getIfPresent(actorId);
51+
if (Objects.nonNull(ref)){
52+
return ref;
53+
}
54+
55+
spawnActor(actorId, client);
56+
ref = new ActorRef(actorId, client);
57+
ACTOR_REF_CACHE.put(actorId, ref);
58+
return ref;
5559
}
5660

5761
public <T extends GeneratedMessageV3> Optional<Object> invoke(String cmd, Class<T> outputType) throws Exception {
@@ -121,42 +125,27 @@ public <T extends GeneratedMessageV3, S extends GeneratedMessageV3> void invokeA
121125
}
122126

123127
public String getActorSystem() {
124-
return this.system;
128+
return this.actorId.getSystem();
125129
}
126130

127131
public String getActorName() {
128-
return this.name;
132+
return this.actorId.getName();
129133
}
130134

131135
public Optional<String> maybeActorParentName() {
132-
return this.parent;
136+
return Optional.ofNullable(this.actorId.getParent());
133137
}
134138

135139
public String getActorParentName() {
136-
return this.parent.get();
137-
}
138-
139-
public boolean isUnnamedActor() {
140-
return Optional.empty().isPresent();
140+
return this.actorId.getParent();
141141
}
142142

143-
private ActorOuterClass.ActorId buildActorId() {
144-
ActorOuterClass.ActorId.Builder actorIdBuilder = ActorOuterClass.ActorId.newBuilder()
145-
.setSystem(this.system)
146-
.setName(this.name);
147-
148-
if (this.parent.isPresent()) {
149-
actorIdBuilder.setParent(this.parent.get());
143+
public boolean isUnNamedActor() {
144+
if (Objects.nonNull(this.actorId.getParent())) {
145+
return true;
150146
}
151147

152-
return actorIdBuilder.build();
153-
}
154-
155-
private void spawnActor() throws Exception {
156-
Protocol.SpawnRequest req = Protocol.SpawnRequest.newBuilder()
157-
.addActors(this.actorId)
158-
.build();
159-
this.client.spawn(req);
148+
return false;
160149
}
161150

162151
private <T extends GeneratedMessageV3, S extends GeneratedMessageV3> Optional<Object> invokeActor(
@@ -181,7 +170,7 @@ private <T extends GeneratedMessageV3, S extends GeneratedMessageV3> Optional<Ob
181170
Any commandArg = Any.pack(argument);
182171

183172
invocationRequestBuilder
184-
.setSystem(ActorOuterClass.ActorSystem.newBuilder().setName(this.system).build())
173+
.setSystem(ActorOuterClass.ActorSystem.newBuilder().setName(this.actorId.getSystem()).build())
185174
.setActor(actorRef)
186175
.setActionName(cmd)
187176
.setValue(commandArg)
@@ -194,7 +183,7 @@ private <T extends GeneratedMessageV3, S extends GeneratedMessageV3> Optional<Ob
194183
case ERROR:
195184
case UNRECOGNIZED:
196185
throw new ActorInvokeException(
197-
String.format("Unknown error when trying to invoke Actor %s", this.name));
186+
String.format("Unknown error when trying to invoke Actor %s", this.getActorName()));
198187
case ACTOR_NOT_FOUND:
199188
throw new ActorNotFoundException();
200189
case OK:
@@ -206,4 +195,27 @@ private <T extends GeneratedMessageV3, S extends GeneratedMessageV3> Optional<Ob
206195

207196
return Optional.empty();
208197
}
198+
199+
private static ActorOuterClass.ActorId buildActorId(String system, String name) {
200+
ActorOuterClass.ActorId.Builder actorIdBuilder = ActorOuterClass.ActorId.newBuilder()
201+
.setSystem(system)
202+
.setName(name);
203+
204+
return actorIdBuilder.build();
205+
}
206+
207+
private static ActorOuterClass.ActorId buildActorId(String system, String name, String parent) {
208+
return ActorOuterClass.ActorId.newBuilder()
209+
.setSystem(system)
210+
.setName(name)
211+
.setParent(parent)
212+
.build();
213+
}
214+
215+
private static void spawnActor(ActorOuterClass.ActorId actorId, SpawnClient client) throws Exception {
216+
Protocol.SpawnRequest req = Protocol.SpawnRequest.newBuilder()
217+
.addActors(actorId)
218+
.build();
219+
client.spawn(req);
220+
}
209221
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package io.eigr.spawn.api.transport;
2+
3+
import lombok.*;
4+
5+
import java.util.concurrent.Executor;
6+
import java.util.concurrent.Executors;
7+
8+
@Getter
9+
@Builder
10+
@NoArgsConstructor
11+
@AllArgsConstructor
12+
@ToString
13+
public class TransportOpts {
14+
15+
@Builder.Default
16+
private String host = "127.0.0.1";
17+
@Builder.Default
18+
private int port = 8091;
19+
@Builder.Default
20+
private String proxyHost = "127.0.0.1";
21+
@Builder.Default
22+
private int proxyPort = 9001;
23+
@Builder.Default
24+
private Executor executor = Executors.newCachedThreadPool();
25+
}

0 commit comments

Comments
 (0)