-
Notifications
You must be signed in to change notification settings - Fork 565
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
feat: Provide Process Instance Search Request API in the Zeebe Client #19500
Conversation
How can the Zeebe Client (upcoming Camunda Client) be used to execute a search request? Basically, the API reflects that a search query consists of three properties:
The API offers a fluent builder to construct a (simple) search query. Additionally, static builders exist that help to construct complex queries and allow the reuse of defined filters. Fluent Builderpublic static void main(String[] args) {
try (ZeebeClient client = ZeebeClientFactory.getZeebeClient()) {
final ProcessInstanceSearchQueryResponse response1 = client.newProcessInstanceQuery()
.filter((f) -> f
.processInstanceKeys(123456L)
.variable((v) -> v.name("foo").eq("abc"))
.variable((v) -> v.name("bar").eq("def")))
.sort((s) -> s.startDate().endDate().asc())
.send()
.join();
}
} Using the fluent builder, a user can specify a search request fluently. This is useful for simple search requests; it's compact and does not require much code. Static Builderspublic static void main(String[] args) {
try (ZeebeClient client = ZeebeClientFactory.getZeebeClient()) {
final ProcessInstanceFilter filter = SearchBuilders.processInstanceFilter((p) -> p
.processInstanceKeys(123456L)
.variable((v) -> v.name("foo").eq("bar"))
.variable((v) -> v.name("bar").eq("def")));
final ProcessInstanceSort sort = SearchBuilders.processInstanceSort()
.startDate().asc();
final var size = 100;
final ProcessInstanceSearchQueryResponse response2 = client.newProcessInstanceQuery()
.filter(filter)
.sort(sort)
.page((p) -> p.size(size))
.send()
.join();
final ProcessInstanceSearchQueryResponse response3 = client.newProcessInstanceQuery()
.filter(filter)
.sort(sort)
.page((p) -> p.size(size).searchAfter(response2.getSortValues().toArray())) // use sort values from previous response3
.send()
.join();
final ProcessInstanceSearchQueryResponse response4 = client.newProcessInstanceQuery()
.filter(filter)
.sort(sort)
.page((p) -> p.size(size).searchAfter(response3.getSortValues().toArray())) // use sort values from previous response4
.send()
.join();
}
} No filterpublic static void main(String[] args) {
try (ZeebeClient client = ZeebeClientFactory.getZeebeClient()) {
final ProcessInstanceSearchQueryResponse response5 = client.newProcessInstanceQuery()
.send()
.join();
}
} When a user has a more complex query and/or wants to collect entities in pages, the static builders can be used. They allow the creation of a filter and sorting fluently, which can then be reused for the next requests to get the pages one after the other. In both cases, the users are not restricted in defining the search request (first sorting, then filtering, and so on). That differs from the existing command API in the Client. There, the commands define one to many steps before executing a command. That way, the user is guided to create a command. IMO, this does not fully apply to search request API, assuming the structure a search request will always have - as mentioned above - it is clear what a user can configure but doesn't have to. |
I haven't looked at the code yet, will do that tomorrow. On a logical level, great proposal, @romansmirnov 👍 Regarding command creation and execution, I think it's fine to have only one level of steps, as they are usually called. The options are all equally optional and can be left out completely. That's like a topology command, with no required options to use, so it's directly a final step. That should be okay. The only thing that looks a bit off is having to use |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, found a minor typo. I saw the fluent and builder approach already in demo application code.
(v) -> | ||
v.name(f.getName()) | ||
.eq(f.getEq()) | ||
.gt(f.getEq()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess .gt(f.getGt())
was meant here.
I liked the approach over the API, looks pretty fluent in terms of proposal to me. 💯 It effectively covers use cases from simple to complex search requests, demonstrating the versatility of the API. I would agree with @tmetzke in the terms of use toArray on the sort values of the previous response. But it can be improved after it works. Great work here 👍 |
Updated the API:
final SearchQueryResponse<ProcessInstance> response = client.newProcessInstanceQuery()
.filter((f) -> f.variable((v) -> v.name("foo").eq(5)))
.sort((s) -> s.endDate().asc())
.page((p) -> p.size(20))
.send()
.join();
final SearchQueryResponse<ProcessInstance> response2 = client.newProcessInstanceQuery()
.filter((f) -> f.variable((v) -> v.name("foo").eq(5)))
.sort((s) -> s.endDate().asc())
.page((p) -> p.size(20).searchAfter(response.page().lastSortValues()))
.send()
.join(); |
final SearchQueryResponse<ProcessInstance> response = client.newProcessInstanceQuery()
.sort((s) -> s.endDate().asc())
.page((p) -> p.size(20))
.send()
.join();
response.items().forEach(System.out::println); returns
|
d4ffa42
to
db2d338
Compare
|
||
@Override | ||
public ProcessInstanceSort startDate() { | ||
return field("startDate"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[❓] If I am not wrong, on Camunda Services, we refer those fields to sort, why we need re-do it here on the SortImpl
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Camunda Services is a server-side implementation, and the sorting there defines on which (index) field sorting must happen.
This code here is used on the client side, which eventually calls the /process-instances/search
endpoint. At this point, the user constructs the search query being serialized into a JSON, for example:
{
"filter": {
"processInstanceKey": 22456786958
},
"sort": [
{ "startDate": "ASC" }
],
"page": {
"limit": 10
}
}
When the Process Instance REST controller receives that request, it must somehow map the client's search request to the actual service, i.e., based on the passed sorting field it will call the respective sort method in the service.
db2d338
to
967c0e8
Compare
967c0e8
to
f1a1901
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks really good overall 👍
I added a couple of understanding questions, nothing that really blocks the PR though.
clients/java/src/main/java/io/camunda/zeebe/client/api/search/ProcessInstanceFilter.java
Outdated
Show resolved
Hide resolved
clients/java/src/main/java/io/camunda/zeebe/client/impl/search/ProcessInstanceFilterImpl.java
Outdated
Show resolved
Hide resolved
/** Start the page from. */ | ||
SearchRequestPage from(final Integer value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ We don't have from
defined in the REST API guidelines so far. What is this used for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can be used for a classic pagination without search after, however, I can remove it if not needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Understood. Do we offer this on the controller/server side?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it offers it already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah OK, I didn't know 👍 Let's keep it then and add it to the REST guidelines 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't add it to the guidelines yet because we weren't sure how complex it would be to add it to the search controllers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@romansmirnov, would you mind adding this to the REST guidelines by creating a proposal, describing how to define and use this in search and response? 🙂 I can take care of documenting this in the guidelines then 👍
Description
Implements a search request API in the Zeebe Client so users can search process instances creating a query, for example
Related issues
closes #