diff --git a/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprHttpClient.java b/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprHttpClient.java index b5a3c5571..51f8f507e 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprHttpClient.java +++ b/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprHttpClient.java @@ -37,7 +37,13 @@ class DaprHttpClient implements DaprClient { public Mono getActorState(String actorType, String actorId, String keyName) { String url = String.format(Constants.ACTOR_STATE_KEY_RELATIVE_URL_FORMAT, actorType, actorId, keyName); Mono responseMono = this.client.invokeApi(DaprHttp.HttpMethods.GET.name(), url, null, "", null); - return responseMono.map(r -> r.getBody()); + return responseMono.map(r -> { + if ((r.getStatusCode() != 200) && (r.getStatusCode() != 204)) { + throw new IllegalStateException( + String.format("Error getting actor state: %s/%s/%s", actorType, actorId, keyName)); + } + return r.getBody(); + }); } /** diff --git a/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprStateAsyncProvider.java b/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprStateAsyncProvider.java index 36fb0bf4f..86f3c1e5e 100644 --- a/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprStateAsyncProvider.java +++ b/sdk-actors/src/main/java/io/dapr/actors/runtime/DaprStateAsyncProvider.java @@ -78,7 +78,7 @@ class DaprStateAsyncProvider { Mono contains(String actorType, ActorId actorId, String stateName) { Mono result = this.daprClient.getActorState(actorType, actorId.toString(), stateName); - return result.map(s -> true).defaultIfEmpty(false); + return result.map(s -> s.length > 0).defaultIfEmpty(false); } /** diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/ActorStateIT.java b/sdk-tests/src/test/java/io/dapr/it/actors/ActorStateIT.java index c2fb89f7e..4418e5e29 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/ActorStateIT.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/ActorStateIT.java @@ -38,12 +38,20 @@ public class ActorStateIT extends BaseIT { 60000); String message = "This is a message to be saved and retrieved."; + String name = "Jon Doe"; ActorId actorId = new ActorId(Long.toString(System.currentTimeMillis())); String actorType = "StatefulActorTest"; logger.debug("Building proxy ..."); ActorProxyBuilder proxyBuilder = new ActorProxyBuilder(actorType, ActorProxy.class); ActorProxy proxy = proxyBuilder.build(actorId); + // Validate conditional read works. + callWithRetry(() -> { + logger.debug("Invoking readMessage where data is not present yet ... "); + String result = proxy.invokeActorMethod("readMessage", String.class).block(); + assertNull(result); + }, 5000); + callWithRetry(() -> { logger.debug("Invoking writeMessage ... "); proxy.invokeActorMethod("writeMessage", message).block(); @@ -69,6 +77,28 @@ public class ActorStateIT extends BaseIT { assertEquals(mydata.value, result.value); }, 5000); + callWithRetry(() -> { + logger.debug("Invoking writeName ... "); + proxy.invokeActorMethod("writeName", name).block(); + }, 5000); + + callWithRetry(() -> { + logger.debug("Invoking readName where data is probably still cached ... "); + String result = proxy.invokeActorMethod("readName", String.class).block(); + assertEquals(name, result); + }, 5000); + + callWithRetry(() -> { + logger.debug("Invoking writeName with empty content... "); + proxy.invokeActorMethod("writeName", "").block(); + }, 5000); + + callWithRetry(() -> { + logger.debug("Invoking readName where empty content is probably still cached ... "); + String result = proxy.invokeActorMethod("readName", String.class).block(); + assertEquals("", result); + }, 5000); + logger.debug("Waiting, so actor can be deactivated ..."); Thread.sleep(10000); @@ -97,5 +127,11 @@ public class ActorStateIT extends BaseIT { assertEquals(mydata.value, result.value); }, 5000); logger.debug("Finished testing actor string state."); + + callWithRetry(() -> { + logger.debug("Invoking readName where empty content is not cached ... "); + String result = newProxy.invokeActorMethod("readName", String.class).block(); + assertEquals("", result); + }, 5000); } } diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/services/springboot/StatefulActor.java b/sdk-tests/src/test/java/io/dapr/it/actors/services/springboot/StatefulActor.java index 13b8fb7c1..5cb92a251 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/services/springboot/StatefulActor.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/services/springboot/StatefulActor.java @@ -11,6 +11,10 @@ public interface StatefulActor { String readMessage(); + void writeName(String something); + + String readName(); + void writeData(MyData something); MyData readData(); diff --git a/sdk-tests/src/test/java/io/dapr/it/actors/services/springboot/StatefulActorImpl.java b/sdk-tests/src/test/java/io/dapr/it/actors/services/springboot/StatefulActorImpl.java index 195438cfc..94d31d05a 100644 --- a/sdk-tests/src/test/java/io/dapr/it/actors/services/springboot/StatefulActorImpl.java +++ b/sdk-tests/src/test/java/io/dapr/it/actors/services/springboot/StatefulActorImpl.java @@ -31,6 +31,20 @@ public class StatefulActorImpl extends AbstractActor implements StatefulActor { return null; } + @Override + public void writeName(String something) { + super.getActorStateManager().set("name", something).block(); + } + + @Override + public String readName() { + if (super.getActorStateManager().contains("name").block()) { + return super.getActorStateManager().get("name", String.class).block(); + } + + return null; + } + @Override public void writeData(MyData something) { super.getActorStateManager().set("mydata", something).block();