@@ -13,7 +13,6 @@ This SDK features:
13
13
- Implement Restate services using either:
14
14
- Java
15
15
- Kotlin coroutines
16
- - Reuse the existing gRPC/Protobuf ecosystem to define service interfaces
17
16
- Deploy Restate services as:
18
17
- Non-blocking HTTP servers
19
18
- On AWS Lambda
@@ -40,55 +39,13 @@ Scaffold a project using the build tool of your choice. For example, with Gradle
40
39
gradle init --type java-application
41
40
```
42
41
43
- Add the dependency [ sdk-api] ( sdk-api ) :
42
+ Add the runtime dependency [ sdk-api] ( sdk-api ) and the annotation processor dependency [ sdk-api-gen ] ( sdk-api-gen ) :
44
43
45
44
```
46
- implementation("dev.restate:sdk-api:0.6.0")
45
+ annotationProcessor("dev.restate:sdk-api-gen:0.9.0")
46
+ implementation("dev.restate:sdk-api:0.9.0")
47
47
```
48
48
49
- Now you need to configure the protobuf plugin to build your Protobuf contracts. For example, with Gradle (Kotlin script):
50
-
51
- ``` kts
52
- import com.google.protobuf.gradle.id
53
-
54
- plugins {
55
- // ...
56
- id(" com.google.protobuf" ) version " 0.9.1"
57
- // ...
58
- }
59
-
60
- dependencies {
61
- // ...
62
- // You need the following dependencies to compile the generated code
63
- implementation(" com.google.protobuf:protobuf-java:3.24.3" )
64
- implementation(" io.grpc:grpc-stub:1.58.0" )
65
- implementation(" io.grpc:grpc-protobuf:1.58.0" )
66
- compileOnly(" org.apache.tomcat:annotations-api:6.0.53" )
67
- }
68
-
69
- // Configure protoc plugin
70
- protobuf {
71
- protoc { artifact = " com.google.protobuf:protoc:3.24.3" }
72
-
73
- plugins {
74
- // The Restate plugin depends on the gRPC generated code
75
- id(" grpc" ) { artifact = " io.grpc:protoc-gen-grpc-java:1.58.0" }
76
- id(" restate" ) { artifact = " dev.restate:protoc-gen-restate:0.6.0:all@jar" }
77
- }
78
-
79
- generateProtoTasks {
80
- all().forEach {
81
- it.plugins {
82
- id(" grpc" )
83
- id(" restate" )
84
- }
85
- }
86
- }
87
- }
88
- ```
89
-
90
- For Maven you can use the [ xolstice Protobuf plugin] ( https://www.xolstice.org/protobuf-maven-plugin/index.html ) .
91
-
92
49
### Setup a project (Kotlin)
93
50
94
51
Scaffold a project using the build tool of your choice. For example, with Gradle (Kotlin script):
@@ -97,149 +54,101 @@ Scaffold a project using the build tool of your choice. For example, with Gradle
97
54
gradle init --type kotlin-application
98
55
```
99
56
100
- Add the dependency [ ` sdk-api-kotlin ` ] ( sdk-api-kotlin ) :
57
+ Add the [ Kotlin symbol processing ] ( https://kotlinlang.org/docs/ksp-quickstart.html#use-your-own-processor-in-a-project ) plugin :
101
58
102
59
```
103
- implementation("dev.restate:sdk-api-kotlin:0.6.0")
104
- ```
105
-
106
- Now you need to configure the protobuf plugin to build your Protobuf contracts. For example, with Gradle (Kotlin script):
107
-
108
- ``` kts
109
- import com.google.protobuf.gradle.id
110
-
111
60
plugins {
112
- // ...
113
- id(" com.google.protobuf" ) version " 0.9.1"
114
- // ...
115
- }
116
-
117
- dependencies {
118
- // ...
119
- // You need the following dependencies to compile the generated code
120
- implementation(" com.google.protobuf:protobuf-java:3.24.3" )
121
- implementation(" com.google.protobuf:protobuf-kotlin:3.24.3" )
122
- implementation(" io.grpc:grpc-stub:1.58.0" )
123
- implementation(" io.grpc:grpc-protobuf:1.58.0" )
124
- implementation(" io.grpc:grpc-kotlin-stub:1.4.0" ) { exclude(" javax.annotation" , " javax.annotation-api" ) }
125
- compileOnly(" org.apache.tomcat:annotations-api:6.0.53" )
126
- }
127
-
128
- // Configure protoc plugin
129
- protobuf {
130
- protoc { artifact = " com.google.protobuf:protoc:3.24.3" }
131
-
132
- plugins {
133
- // The gRPC Kotlin plugin depends on the gRPC generated code
134
- id(" grpc" ) { artifact = " io.grpc:protoc-gen-grpc-java:1.58.0" }
135
- id(" restate" ) { artifact = " dev.restate:protoc-gen-restate:0.6.0:all@jar" }
136
- }
137
-
138
- generateProtoTasks {
139
- all().forEach {
140
- it.plugins {
141
- id(" grpc" )
142
- id(" restate" ) {
143
- option(" kotlin" )
144
- }
145
- }
146
- it.builtins {
147
- // The Kotlin codegen depends on the Java generated code
148
- java {}
149
- id(" kotlin" )
150
- }
151
- }
152
- }
61
+ id("com.google.devtools.ksp") version "1.9.22-1.0.18"
153
62
}
154
63
```
155
64
156
- ### Add the Protobuf contract
157
-
158
- Now you can add the Protobuf contract under ` src/main/proto ` . For example:
159
-
160
- ``` protobuf
161
- syntax = "proto3";
162
- package greeter;
65
+ Add the runtime dependency [ sdk-api-kotlin] ( sdk-api-kotlin ) and the ksp dependency [ sdk-api-gen] ( sdk-api-kotlin-gen ) :
163
66
164
- option java_package = "my.greeter";
165
- option java_outer_classname = "GreeterProto";
166
-
167
- import "dev/restate/ext.proto";
168
-
169
- service Greeter {
170
- option (dev.restate.ext.service_type) = KEYED;
171
-
172
- rpc Greet (GreetRequest) returns (GreetResponse);
173
- }
174
-
175
- message GreetRequest {
176
- string name = 1 [(dev.restate.ext.field) = KEY];
177
- }
178
-
179
- message GreetResponse {
180
- string message = 1;
181
- }
67
+ ```
68
+ ksp("dev.restate:sdk-api-kotlin-gen:0.9.0")
69
+ implementation("dev.restate:sdk-api-kotlin:0.9.0")
182
70
```
183
71
184
- By using the Gradle or Maven plugin, the code is automatically re-generated on every build.
185
-
186
- ### Implement the service (Java)
72
+ ### Implement your first Restate component (Java)
187
73
188
- Implement the service in a new class, for example:
74
+ Implement your first virtual object in a new class, for example:
189
75
190
76
``` java
191
- public class Greeter extends GreeterRestate .GreeterRestateImplBase {
77
+ import dev.restate.sdk.ObjectContext ;
78
+ import dev.restate.sdk.annotation.Handler ;
79
+ import dev.restate.sdk.annotation.VirtualObject ;
80
+ import dev.restate.sdk.common.CoreSerdes ;
81
+ import dev.restate.sdk.common.StateKey ;
82
+
83
+ @VirtualObject
84
+ public class Greeter {
192
85
193
86
private static final StateKey<Long > COUNT = StateKey . of(" total" , CoreSerdes . LONG );
194
87
195
- @Override
196
- public GreetResponse greet (RestateContext ctx , GreetRequest request ) {
88
+ @Handler
89
+ public String greet (ObjectContext ctx , String name ) {
197
90
long count = ctx. get(COUNT ). orElse(0L );
198
91
ctx. set(COUNT , count + 1 );
199
92
200
- return GreetResponse . newBuilder()
201
- .setMessage(String . format(" Hello %s for the %d time!" , request. getName(), count))
202
- .build();
93
+ return String . format(" Hello %s for the %d time!" , name, count);
203
94
}
204
95
}
205
96
```
206
97
207
- If you want to use POJOs for state, check [ how to use Jackson] ( #state -serde-using- jackson) .
98
+ When using composite types/ POJOs for input/output, [ Jackson Databind ] ( https://github.com/FasterXML/jackson ) will be used. The Jackson dependency is not automatically included, you must add it with [ ` sdk-serde-jackson ` ] ( sdk -serde-jackson) :
208
99
209
- ### Implement the service (Kotlin)
100
+ ```
101
+ implementation("dev.restate:sdk-serde-jackson:0.9.0")
102
+ ```
210
103
211
- Implement the service in a new class, for example:
104
+ If you want to store types/POJOs in state, use ` JacksonSerdes ` :
105
+
106
+ ``` java
107
+ private static final StateKey<Person > PERSON = StateKey . of(" person" , JacksonSerdes . of(Person . class));
108
+ ```
109
+
110
+ ### Implement your first Restate component (Kotlin)
111
+
112
+ Implement your first virtual object in a new class, for example:
212
113
213
114
``` kotlin
214
- class Greeter : GreeterRestateKtImplBase () {
115
+ import dev.restate.sdk.annotation.Handler
116
+ import dev.restate.sdk.annotation.VirtualObject
117
+ import dev.restate.sdk.common.StateKey
118
+ import dev.restate.sdk.kotlin.KtSerdes
119
+ import dev.restate.sdk.kotlin.ObjectContext
120
+
121
+ @VirtualObject
122
+ class Greeter {
215
123
companion object {
216
- private val COUNT = StateKey .of(" total" , CoreSerdes . LONG )
124
+ private val COUNT = StateKey .of< Long > (" total" , KtSerdes .json() )
217
125
}
218
126
219
- override suspend fun greet (context : RestateContext , request : GreetRequest ): GreetResponse {
127
+ @Handler
128
+ suspend fun greet (context : ObjectContext , name : String ): String {
220
129
val count = context.get(COUNT ) ? : 0L
221
130
context.set(COUNT , count + 1 )
222
- return greetResponse { message = " Hello ${request. name} for the $count time!" }
131
+ return " Hello $name for the $count time!"
223
132
}
224
133
}
225
134
```
226
135
227
- If you want to use POJOs for state, check [ how to use Jackson ] ( #state-serde-using-jackson ) .
136
+ When using composite data types for input/output, [ ` kotlinx.serialization ` ] ( https://github.com/Kotlin/kotlinx.serialization?tab=readme-ov-file#setup ) will be used .
228
137
229
138
### Deploy the service (HTTP Server)
230
139
231
140
To deploy the Restate service as HTTP server, add [ ` sdk-http-vertx ` ] ( sdk-http-vertx ) to the dependencies. For example, in Gradle:
232
141
233
142
```
234
- implementation("dev.restate:sdk-http-vertx:0.6 .0")
143
+ implementation("dev.restate:sdk-http-vertx:0.9 .0")
235
144
```
236
145
237
146
To deploy the service, add the following code to the ` main ` . For example in Java:
238
147
239
148
``` java
240
149
public static void main(String [] args) {
241
150
RestateHttpEndpointBuilder . builder()
242
- .withService (new Greeter ())
151
+ .bind (new Greeter ())
243
152
.buildAndListen();
244
153
}
245
154
```
@@ -249,7 +158,7 @@ In Kotlin:
249
158
``` kotlin
250
159
fun main () {
251
160
RestateHttpEndpointBuilder .builder()
252
- .withService (Greeter ())
161
+ .bind (Greeter ())
253
162
.buildAndListen()
254
163
}
255
164
```
@@ -265,7 +174,7 @@ gradle run
265
174
To deploy the Restate service as Lambda, add [ ` sdk-lambda ` ] ( sdk-lambda ) to the dependencies. For example, in Gradle:
266
175
267
176
```
268
- implementation("dev.restate:sdk-lambda:0.6 .0")
177
+ implementation("dev.restate:sdk-lambda:0.9 .0")
269
178
```
270
179
271
180
Configure the build tool to generate Fat-JARs, which are required by AWS Lambda to correctly load the JAR. For example, using Gradle:
@@ -285,7 +194,7 @@ Now create the Lambda handler invoking the service. For example, in Java:
285
194
public class MyLambdaHandler extends BaseRestateLambdaHandler {
286
195
@Override
287
196
public void register (RestateLambdaEndpointBuilder builder ) {
288
- builder. withService (new Greeter ());
197
+ builder. bind (new Greeter ());
289
198
}
290
199
}
291
200
```
@@ -295,7 +204,7 @@ In Kotlin:
295
204
``` kotlin
296
205
class MyLambdaHandler : BaseRestateLambdaHandler {
297
206
override fun register (builder : RestateLambdaEndpointBuilder ) {
298
- builder.withService (Greeter ())
207
+ builder.bind (Greeter ())
299
208
}
300
209
}
301
210
```
@@ -310,22 +219,6 @@ You can now upload the generated Jar in AWS Lambda, and configure `MyLambdaHandl
310
219
311
220
### Additional setup
312
221
313
- #### State ser/de using Jackson
314
-
315
- State ser/de is defined by the interface ` Serde ` . If you want to use [ Jackson Databind] ( https://github.com/FasterXML/jackson ) to ser/de POJOs to JSON, add the dependency [ ` sdk-serde-jackson ` ] ( sdk-serde-jackson ) .
316
-
317
- For example, in Gradle:
318
-
319
- ```
320
- implementation("dev.restate:sdk-serde-jackson:0.6.0")
321
- ```
322
-
323
- And then use ` JacksonSerdes ` :
324
-
325
- ``` java
326
- private static final StateKey<Person > PERSON = StateKey . of(" person" , JacksonSerdes . of(Person . class));
327
- ```
328
-
329
222
#### Logging
330
223
331
224
The SDK uses log4j2 as logging facade. To enable logging, add the ` log4j2 ` implementation to the dependencies:
@@ -433,12 +326,6 @@ To publish local snapshots of the project:
433
326
./gradlew -DskipSigning publishToMavenLocal
434
327
```
435
328
436
- To update the [ ` proto ` ] ( https://github.com/restatedev/proto/ ) git subtree:
437
-
438
- ``` shell
439
- git subtree pull --prefix sdk-common/src/main/proto/ git@github.com:restatedev/proto.git main --squash
440
- ```
441
-
442
329
To update the [ ` service-protocol ` ] ( https://github.com/restatedev/service-protocol/ ) git subtree:
443
330
444
331
``` shell
0 commit comments