Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
a891637
first impl
Apr 29, 2026
e9ff082
added kphp rpc client bench
Apr 30, 2026
bfad75b
break in switch + different debug exit codes
May 5, 2026
f8e68a8
null timeout in bench
May 5, 2026
f6ad7a2
rpc send functions now common functions instead of coroutines
May 5, 2026
14de242
remove one coroutine on rpc response fetch
May 6, 2026
b2905d8
removed test trash
May 20, 2026
689ac2c
error handling
Jun 15, 2026
d872d49
rpc_queue_push
Jun 15, 2026
71675e1
kphp::rpc::request_info
Jun 15, 2026
35393dd
fmt
Jun 17, 2026
c26c025
added RpcKind + better docs
Jun 18, 2026
d87d381
query_handle
Jun 19, 2026
cb2c928
send_and_get_handle
Jun 19, 2026
f3bcb05
refactored query_handle a bit
Jun 19, 2026
63be316
refactorrr
Jun 21, 2026
1195230
k2_rpc_get_response_size() and k2_rpc_fetch_response() now return `EA…
Jun 21, 2026
e429646
[EXPERIMENTAL] removed ignore_answer_coroutine
Jun 23, 2026
b291078
regularize_extra_headers
Jun 26, 2026
4a1c674
added query_handle::wait_for_response
Jun 29, 2026
c4a05a2
fixed zeroing query_handle in rpc_queue_push(..)
Jul 2, 2026
3d9b41b
insert ignore_answer requests to rpc_query_handles
Jul 15, 2026
48077a3
issues
Jul 17, 2026
688a5f6
fmt
Jul 17, 2026
d6a1093
fmt
Jul 17, 2026
a46ce90
refactored kphp::rpc::query_handle
Jul 21, 2026
e63879f
removed rpc-query-handle.cpp
Jul 21, 2026
7cce3ea
fixed nullptr request_buffer, fixed <=0 timeout handling, error becam…
Jul 21, 2026
6b324e5
query_handle: response type now std::span<std::byte>
Jul 21, 2026
030b7db
time utils fixes
Jul 22, 2026
063caf1
fmt
Jul 22, 2026
0a19cd9
fmt
Jul 22, 2026
e7d21b7
query_handle -> query; removed error description for query::get_respo…
Jul 22, 2026
d6003ac
kphp::rpc::query::get_ready_response() takes templated response_alloc…
Jul 22, 2026
2869178
TODO
Jul 22, 2026
cb4017c
ResponseAllocator and ResponseDeleter
Jul 23, 2026
f619dfd
ResponseBufferProvider; removed query::wait_for_response; returned re…
Jul 24, 2026
918e9c3
request_buffer is allocated for requests more than `StringLibContext:…
Jul 24, 2026
93cbfed
fmt
Jul 24, 2026
23dd2df
fmt
Jul 24, 2026
67f393e
fmt
Jul 24, 2026
ebc31f7
k2_rpc_fetch_response may return `ENOBUFS`
Jul 24, 2026
3c08cd9
fixed issues
Jul 28, 2026
edd5bef
better docs
Jul 28, 2026
3d27d11
removed extra includes and comments
Jul 31, 2026
08997b8
const refs for send functions + better request_buffer workaround
Aug 11, 2026
0725fc2
better k2-header.h docs + fixed leaked rpc_responses_extra_info entri…
Aug 11, 2026
248415f
II fixes
Aug 11, 2026
f051320
h
Aug 11, 2026
5bef88c
fmt
Aug 11, 2026
63abf8f
reserve dest actors flags header before stiring rpc client request, t…
Aug 12, 2026
3f6a1cb
fixed ignored new header offset in request_buffer
Aug 13, 2026
2144d79
cleareeeeer
Aug 13, 2026
ba1c759
query::response now not a member function, but takes query by value
Aug 13, 2026
082ca7e
fmt
Aug 13, 2026
55eaee6
fmt
Aug 13, 2026
8ca5a7c
AGAIN THIS MISTAKE
Aug 13, 2026
4b2294d
self
Aug 13, 2026
79fdd40
log returned null from typed fetcher with no rasied error
Aug 14, 2026
e30408c
DEBUG LOOOOOOOOOOOGS
Aug 14, 2026
d754bbc
returned buffer copying
Aug 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions builtin-functions/kphp-light/stdlib/rpc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,14 @@ final class KphpRpcRequestsExtraInfo {
public function get ();
}

/** @kphp-extern-func-info interruptible */
function rpc_send_requests($actor ::: string,
$arr ::: array,
$timeout ::: ?float,
$ignore_answer ::: bool,
\KphpRpcRequestsExtraInfo $requests_extra_info,
$need_responses_extra_info ::: bool) ::: int[];

/** @kphp-extern-func-info tl_common_h_dep interruptible */
/** @kphp-extern-func-info tl_common_h_dep */
function rpc_send_typed_query_requests($actor ::: string, @tl\RpcFunction[] $query_functions,
$timeout ::: ?float,
$ignore_answer ::: bool,
Expand Down
22 changes: 0 additions & 22 deletions runtime-light/components/kphp/state/instance-state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include "runtime-light/components/kphp/state/component-state.h"
#include "runtime-light/core/globals/php-init-scripts.h"
#include "runtime-light/core/globals/php-script-globals.h"
#include "runtime-light/coroutine/await-set.h"
#include "runtime-light/coroutine/task.h"
#include "runtime-light/k2-platform/k2-api.h"
#include "runtime-light/server/cli/init-functions.h"
Expand All @@ -29,7 +28,6 @@
#include "runtime-light/stdlib/diagnostics/logs.h"
#include "runtime-light/stdlib/fork/fork-functions.h"
#include "runtime-light/stdlib/fork/fork-state.h"
#include "runtime-light/stdlib/rpc/rpc-client-state.h"
#include "runtime-light/stdlib/time/time-functions.h"
#include "runtime-light/streams/read-ext.h"
#include "runtime-light/streams/stream.h"
Expand Down Expand Up @@ -221,26 +219,6 @@ kphp::coro::task<> InstanceState::run_instance_epilogue() noexcept {
}
shutdown_state_ = shutdown_state::finished;

/*
* Unlike regular RPC requests whose results the user code waits for via rpc_fetch_responses,
* thereby guaranteeing they are sent, the user code does not wait for requests sent with the
* ignore_answer flag. Therefore, we can’t guarantee that the coroutines responsible for
* sending ignore_answer requests have finished. This means the requests might not be sent
* if the instance terminates.
*
* This await suspends the current coroutine until all pending ignore_answer requests are
* fully sent. While suspended, other forks and coroutines may continue running.
*
* After this call completes, delivery of all ignore_answer requests is guaranteed.
*/
{
auto& rpc_client_instance_st{RpcClientInstanceState::get()};
auto ignore_answer_request_await_set{std::exchange(rpc_client_instance_st.ignore_answer_request_awaiter_tasks, kphp::coro::await_set<void>{})};
while (!ignore_answer_request_await_set.empty()) {
co_await ignore_answer_request_await_set.next();
}
}

// Stop session with internal Web component
if (auto& web_state{WebInstanceState::get()}; web_state.session.has_value()) {
web_state.session_is_finished = true;
Expand Down
29 changes: 29 additions & 0 deletions runtime-light/k2-platform/k2-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ inline constexpr int32_t errno_enoent = ENOENT;
inline constexpr int32_t errno_eopnotsupp = EOPNOTSUPP;
inline constexpr int32_t errno_ealready = EALREADY;
inline constexpr int32_t errno_einprogress = EINPROGRESS;
inline constexpr int32_t errno_eagain = EAGAIN;

using descriptor = uint64_t;
inline constexpr k2::descriptor INVALID_PLATFORM_DESCRIPTOR = 0;
Expand All @@ -80,6 +81,8 @@ using PollStatus = PollStatus;

using ImageInfo = ImageInfo;

using RpcKind = RpcKind;

using ControlFlags = ControlFlags;

inline const ImageInfo* describe() noexcept {
Expand Down Expand Up @@ -210,6 +213,32 @@ inline int32_t component_access(std::string_view component_name) noexcept {
return k2_component_access(component_name.size(), component_name.data());
}

inline std::expected<k2::descriptor, int32_t> rpc_send_request(std::string_view actor_name, std::span<const std::byte> request_buffer,
k2::RpcKind rpc_kind) noexcept {
k2::descriptor descriptor{};
if (auto error_code{
k2_rpc_send_request(actor_name.data(), actor_name.size(), request_buffer.data(), request_buffer.size(), rpc_kind, std::addressof(descriptor))};
error_code != k2::errno_ok) {
return std::unexpected{error_code};
}
return {descriptor};
}

inline std::expected<size_t, int32_t> rpc_get_response_size(k2::descriptor descriptor) noexcept {
size_t size{};
if (auto error_code{k2_rpc_get_response_size(descriptor, std::addressof(size))}; error_code != k2::errno_ok) {
return std::unexpected{error_code};
}
return {size};
}

inline std::expected<void, int32_t> rpc_fetch_response(k2::descriptor descriptor, std::span<std::byte> buffer) noexcept {
if (auto error_code{k2_rpc_fetch_response(descriptor, buffer.data(), buffer.size())}; error_code != k2::errno_ok) {
return std::unexpected{error_code};
}
return {};
}

inline void stream_status(k2::descriptor descriptor, StreamStatus* status) noexcept {
k2_stream_status(descriptor, status);
}
Expand Down
55 changes: 54 additions & 1 deletion runtime-light/k2-platform/k2-header.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ enum UpdateStatus {
NewDescriptor = 2,
};

enum RpcKind {
TL_RPC = 0,
};

// k2-node will attempt to extract `compiler_version` from `extra_info` to add as a tag to the `k2_image_version` metric
struct ImageInfo {
// Base
Expand Down Expand Up @@ -425,17 +429,66 @@ int32_t k2_unlink(const char* path, size_t path_len);
*/
int32_t k2_component_access(size_t name_len, const char* name);

/**
* Try to send rpc request to actor. On success, write descriptor of the corresponding rpc query to `rpc_d`.
* This descriptor should be later used to call `k2_rpc_get_response_size` and `k2_rpc_fetch_response`.
* On failure return positive libc-like errno.
*
* The request is copied synchronously, so the caller may reuse the buffer after return.
*
* The returned descriptor is pollable like a stream - `k2_take_update` may return update on it when the response is ready
* and `k2_stream_status` can be called on it, returning read status is `Blocked` when response is not ready yet
* and `Available` when it is ready.
*
* @return return `0` on success. libc-like `errno` otherwise.
*
* Possible `errno` values:
* `EMFILE` => max descriptors count achieved.
* `ENODEV` => rpc client module is not available.
* `EINVAL` => invalid `actor_name` or request.
*/
int32_t k2_rpc_send_request(const char* actor_name, size_t actor_name_len, const void* request_ptr, size_t request_size, enum RpcKind rpc_kind,
uint64_t* rpc_d);

/**
* Try to get response size for the corresponding query of this `rpc_d`.
* Write 0 to `response_size` and return `EAGAIN` if response is not ready yet.
* Write positive response size value to `response_size` if response is ready and return 0.
*
* @return return `0` on success. libc-like `errno` otherwise
*
* Possible `errno` values:
* `EINVAL` => invalid `rpc_d` descriptor, for example, it is unknown descriptor, or not rpc descriptor.
Comment thread
apolyakov marked this conversation as resolved.
* `EAGAIN` => response is not ready yet.
*/
int32_t k2_rpc_get_response_size(uint64_t rpc_d, size_t* response_size);

/**
* Try to fetch response for the corresponding query of this `rpc_d`. If response is ready, write it to `buf` and return 0.
* Return `EAGAIN` if response is not ready yet and write nothing. Return `ENOBUFS` if `buf_size` < response length.
* User should get response size by calling `k2_rpc_get_response_size` first.
*
* @return return `0` on success. libc-like `errno` otherwise
*
* Possible `errno` values:
* `EINVAL` => invalid `rpc_d` descriptor, for example, it is unknown descriptor, or not rpc descriptor.
* `EAGAIN` => response is not ready yet.
* `ENOBUFS` => provided response buffer is not big enough, (`buf_size` < `response_size` value written by `k2_rpc_get_response_size`).
*/
int32_t k2_rpc_fetch_response(uint64_t rpc_d, void* buf, size_t buf_size);

/**
* If the write or read status is `Blocked` - then the platform ensures that
* the component receives this `stream_d` via `k2_take_update` when the status is
* no longer `Blocked` ("edge-triggered epoll"-like behaviour).
* Can be called on stream or rpc query descriptors.
*
* `status` will be filled with actual descriptor status on of success.
* `s->libc_errno` used to represent errors.
*
* Some `errno` examples:
* `EBADF` => d is not valid(never was valid or used after free)
* `EBADR` => d is valid descriptor, but not a stream (probably, timer)
* `EBADR` => d is valid descriptor, but not a stream or rpc query (probably, timer)
*/
void k2_stream_status(uint64_t stream_d, struct StreamStatus* status);

Expand Down
Loading
Loading