Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add promises support #1515

Merged
merged 1 commit into from
May 20, 2024
Merged

Conversation

slinkydeveloper
Copy link
Contributor

Fix #1513. This implements the new promises api in the service-protocol

@slinkydeveloper slinkydeveloper changed the title Add promises support [WIP] Add promises support May 14, 2024
@slinkydeveloper slinkydeveloper changed the title [WIP] Add promises support Add promises support May 15, 2024
Copy link
Contributor

@tillrohrmann tillrohrmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for creating this PR @slinkydeveloper. The changes look good to me. The one question I have is about the lifecycle of promises. I couldn't find how these promises are being cleaned up. If they are kept around forever, how are we gonna make handlers work that repeatedly create promises? I guess in the first version only workflows will use this feature. After a workflow is cleaned up I assume that a new run will try to create the same promise again.

crates/partition-store/src/promise_table/mod.rs Outdated Show resolved Hide resolved
crates/partition-store/src/promise_table/mod.rs Outdated Show resolved Hide resolved
crates/service-protocol/src/message/header.rs Show resolved Hide resolved
crates/storage-api/src/promise_table/mod.rs Outdated Show resolved Hide resolved
crates/storage-api/src/promise_table/mod.rs Outdated Show resolved Hide resolved
#[derive(Debug, Clone, PartialEq)]
pub enum PromiseState {
Completed(EntryResult),
NotCompleted(Vec<JournalEntryId>),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are the JournalEntryIds being used for? Maybe add a bit of documentation for this variant because it does not seem super obvious.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to myself: Those are the entries of another invocation's journal of the same service instance which are awaiting the promise and want to be notified in case it completes.

);

if let Some(service_id) =
invocation_metadata.invocation_target.as_keyed_service_id()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand it correctly that the promise feature only allows a service instance to access promises that were created by itself? I guess if we wanted to do it generally, one would have to introduce a new message that can retrieve the result from a different partition.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do I understand it correctly that the promise feature only allows a service instance to access promises that were created by itself?

Yes this is how it's modeled in the service protocol entry message too (it doesn't have the service name/service key of the promise holder). The idea is that people should not expose promises to foreign services as api surface, but should rely on shared handlers for that.

Comment on lines +1418 to +1425
warn!(
"Trying to process entry {} for a target that has no promises",
journal_entry.header().as_entry_type()
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit unrelated. I am not sure about the warn level here because technically this situation can easily happen when a user writes an incorrect handler. However, this does not mean that the runtime is in anyway in danger which I would usually associate with a log message on warn level (e.g. disk space is running full, not able to connect to the cluster controller, etc.).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit unrelated. I am not sure about the warn level here because technically this situation can easily happen when a user writes an incorrect handler.

This can happen only in case the SDK is buggy and exposes the promise apis to non-workflow Context, this is a similar case to creating GetState inside a regular service.

state: PromiseState::Completed(_),
}) => {
// Conflict!
(&CONFLICT_INVOCATION_ERROR).into()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity: How will this error surface to the user? Will it be a terminal error or returned as false on the complete call?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now it seems reasonable to return a terminal error. There might be other situations where we could fail to complete the promise that were discussed as well, e.g. fail completing a promise if the workflow didn't started yet.

@slinkydeveloper
Copy link
Contributor Author

The one question I have is about the lifecycle of promises. I couldn't find how these promises are being cleaned up. If they are kept around forever, how are we gonna make handlers work that repeatedly create promises? I guess in the first version only workflows will use this feature. After a workflow is cleaned up I assume that a new run will try to create the same promise again.

This is exactly the reason why these promises will be for the foreseable future a workflow only feature, because the lifecycle question is still open for virtual objects. As soon as I rebase this PR, I'll add the command to cleanup the promises when the workflow is cleaned up (if you remember, there was a todo for that in the other workflow PR)

@slinkydeveloper
Copy link
Contributor Author

slinkydeveloper commented May 16, 2024

I updated this PR with the feedback + integrated with the previous workflow PR @tillrohrmann

Copy link
Contributor

@tillrohrmann tillrohrmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work @slinkydeveloper. LGTM. +1 for merging :-)

crates/partition-store/src/promise_table/mod.rs Outdated Show resolved Hide resolved
crates/partition-store/src/promise_table/mod.rs Outdated Show resolved Hide resolved
crates/partition-store/src/promise_table/mod.rs Outdated Show resolved Hide resolved
crates/partition-store/tests/promise_table_test/mod.rs Outdated Show resolved Hide resolved
pub enum PromiseState {
Completed(EntryResult),
NotCompleted(
// Journal entries listening for this promise to be completed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a limitation for which journals/invocations can listen for a promise (invocations to the same service instance vs. an arbitrary invocation)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In principle not, the implementation of this table is built such that any invocation from any partition could listen to any promise. But the restriction currently exists in the service protocol entry, and transitively in the PP commands.

crates/types/src/errors.rs Show resolved Hide resolved
@slinkydeveloper slinkydeveloper merged commit bdf0106 into restatedev:main May 20, 2024
4 checks passed
@slinkydeveloper slinkydeveloper deleted the issues/1513 branch May 20, 2024 07:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement the new promises api
2 participants