Skip to content

Commit af48116

Browse files
Add state keys support (#14)
* Add state keys support * Remove Kafka from exclusions
1 parent d6cc93d commit af48116

File tree

7 files changed

+49
-38
lines changed

7 files changed

+49
-38
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ doc = false
1414
[dependencies]
1515
pyo3 = { version = "0.22.0", features = ["extension-module"] }
1616
tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] }
17-
restate-sdk-shared-core = { version = "0.0.4" }
17+
restate-sdk-shared-core = "0.0.5"

python/restate/server_context.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ async def await_point():
205205
return await_point() # do not await here, the caller will do it.
206206

207207
def state_keys(self) -> Awaitable[List[str]]:
208-
raise NotImplementedError
208+
return self.create_poll_coroutine(self.vm.sys_get_state_keys()) # type: ignore
209209

210210
def set(self, name: str, value: T, serde: Serde[T] = JsonSerde()) -> None:
211211
"""Set the value associated with the given name."""

python/restate/vm.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
from dataclasses import dataclass
1717
import typing
18-
from restate._internal import PyVM, PyFailure, PySuspended, PyVoid # pylint: disable=import-error,no-name-in-module
18+
from restate._internal import PyVM, PyFailure, PySuspended, PyVoid, PyStateKeys # pylint: disable=import-error,no-name-in-module
1919

2020
@dataclass
2121
class Invocation:
@@ -110,6 +110,9 @@ def take_async_result(self, handle: typing.Any) -> AsyncResultType:
110110
if isinstance(result, bytes):
111111
# success with a non empty value
112112
return result
113+
if isinstance(result, PyStateKeys):
114+
# success with state keys
115+
return result.keys
113116
if isinstance(result, PyFailure):
114117
# a terminal failure
115118
code = result.code
@@ -179,6 +182,17 @@ def sys_get_state(self, name) -> int:
179182
"""
180183
return self.vm.sys_get_state(name)
181184

185+
186+
def sys_get_state_keys(self) -> int:
187+
"""
188+
Retrieves all keys.
189+
190+
Returns:
191+
The state keys
192+
"""
193+
return self.vm.sys_get_state_keys()
194+
195+
182196
def sys_set_state(self, name: str, value: bytes):
183197
"""
184198
Sets a key-value binding.

src/lib.rs

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
use pyo3::create_exception;
22
use pyo3::prelude::*;
33
use pyo3::types::{PyBytes, PyNone};
4-
use restate_sdk_shared_core::{
5-
AsyncResultHandle, CoreVM, Failure, Header, IdentityHeaderMap, IdentityVerifier, Input,
6-
NonEmptyValue, ResponseHead, RunEnterResult, SuspendedOrVMError, TakeOutputResult, Target,
7-
VMError, Value, VM,
8-
};
4+
use restate_sdk_shared_core::{AsyncResultHandle, CoreVM, Failure, Header, IdentityVerifier, Input, NonEmptyValue, ResponseHead, RunEnterResult, SuspendedOrVMError, TakeOutputResult, Target, VMError, Value, VM};
95
use std::borrow::Cow;
10-
use std::convert::Infallible;
116
use std::time::Duration;
7+
128
// Data model
139

1410
#[pyclass]
@@ -103,6 +99,13 @@ impl From<PyFailure> for Failure {
10399
}
104100
}
105101

102+
#[pyclass]
103+
#[derive(Clone)]
104+
struct PyStateKeys {
105+
#[pyo3(get, set)]
106+
keys: Vec<String>
107+
}
108+
106109
#[pyclass]
107110
pub struct PyInput {
108111
#[pyo3(get, set)]
@@ -233,6 +236,9 @@ impl PyVM {
233236
Ok(Some(Value::Failure(f))) => {
234237
Ok(PyFailure::from(f).into_py(py).into_bound(py).into_any())
235238
}
239+
Ok(Some(Value::StateKeys(keys))) => {
240+
Ok(PyStateKeys {keys}.into_py(py).into_bound(py).into_any())
241+
}
236242
}
237243
}
238244

@@ -248,7 +254,17 @@ impl PyVM {
248254
) -> Result<PyAsyncResultHandle, PyVMError> {
249255
self_
250256
.vm
251-
.sys_get_state(key)
257+
.sys_state_get(key)
258+
.map(Into::into)
259+
.map_err(Into::into)
260+
}
261+
262+
fn sys_get_state_keys(
263+
mut self_: PyRefMut<'_, Self>,
264+
) -> Result<PyAsyncResultHandle, PyVMError> {
265+
self_
266+
.vm
267+
.sys_state_get_keys()
252268
.map(Into::into)
253269
.map_err(Into::into)
254270
}
@@ -260,16 +276,16 @@ impl PyVM {
260276
) -> Result<(), PyVMError> {
261277
self_
262278
.vm
263-
.sys_set_state(key, buffer.as_bytes().to_vec())
279+
.sys_state_set(key, buffer.as_bytes().to_vec())
264280
.map_err(Into::into)
265281
}
266282

267283
fn sys_clear_state(mut self_: PyRefMut<'_, Self>, key: String) -> Result<(), PyVMError> {
268-
self_.vm.sys_clear_state(key).map_err(Into::into)
284+
self_.vm.sys_state_clear(key).map_err(Into::into)
269285
}
270286

271287
fn sys_clear_all_state(mut self_: PyRefMut<'_, Self>) -> Result<(), PyVMError> {
272-
self_.vm.sys_clear_all_state().map_err(Into::into)
288+
self_.vm.sys_state_clear_all().map_err(Into::into)
273289
}
274290

275291
fn sys_sleep(
@@ -484,21 +500,6 @@ struct PyIdentityVerifier {
484500
verifier: IdentityVerifier,
485501
}
486502

487-
struct PyIdentityHeaders(Vec<(String, String)>);
488-
489-
impl IdentityHeaderMap for PyIdentityHeaders {
490-
type Error = Infallible;
491-
492-
fn extract(&self, name: &str) -> Result<Option<&str>, Self::Error> {
493-
for (k, v) in &self.0 {
494-
if k.eq_ignore_ascii_case(name) {
495-
return Ok(Some(v));
496-
}
497-
}
498-
Ok(None)
499-
}
500-
}
501-
502503
// Exceptions
503504
create_exception!(
504505
restate_sdk_python_core,
@@ -531,7 +532,7 @@ impl PyIdentityVerifier {
531532
) -> PyResult<()> {
532533
self_
533534
.verifier
534-
.verify_identity(&PyIdentityHeaders(headers), &path)
535+
.verify_identity(&headers, &path)
535536
.map_err(|e| IdentityVerificationException::new_err(e.to_string()))
536537
}
537538
}
@@ -549,6 +550,7 @@ fn _internal(m: &Bound<'_, PyModule>) -> PyResult<()> {
549550
m.add_class::<PyFailure>()?;
550551
m.add_class::<PyInput>()?;
551552
m.add_class::<PyVoid>()?;
553+
m.add_class::<PyStateKeys>()?;
552554
m.add_class::<PySuspended>()?;
553555
m.add_class::<PyVM>()?;
554556
m.add_class::<PyIdentityVerifier>()?;

test-services/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ FROM ghcr.io/pyo3/maturin AS build-sdk
44

55
WORKDIR /usr/src/app
66

7-
COPY --exclude=test-services/ . .
7+
COPY . .
88

99
RUN maturin build --out dist --interpreter python3.12
1010

test-services/exclusions.yaml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,8 @@
11
exclusions:
22
"alwaysSuspending":
33
- "dev.restate.sdktesting.tests.AwaitTimeout"
4-
- "dev.restate.sdktesting.tests.State"
54
"default":
65
- "dev.restate.sdktesting.tests.AwaitTimeout"
7-
- "dev.restate.sdktesting.tests.KafkaIngress"
8-
- "dev.restate.sdktesting.tests.State"
9-
"lazyState":
10-
- "dev.restate.sdktesting.tests.State"
6+
"lazyState": []
117
"singleThreadSinglePartition":
128
- "dev.restate.sdktesting.tests.AwaitTimeout"
13-
- "dev.restate.sdktesting.tests.State"

0 commit comments

Comments
 (0)