Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
88506ca
first impl
Apr 29, 2026
685f761
added kphp rpc client bench
Apr 30, 2026
b23ffce
break in switch + different debug exit codes
May 5, 2026
cd291fe
null timeout in bench
May 5, 2026
3d42f85
rpc send functions now common functions instead of coroutines
May 5, 2026
c3ea75e
remove one coroutine on rpc response fetch
May 6, 2026
2f106c3
removed test trash
May 20, 2026
2545767
error handling
Jun 15, 2026
6d8a1db
rpc_queue_push
Jun 15, 2026
9d874b3
kphp::rpc::request_info
Jun 15, 2026
e683f67
fmt
Jun 17, 2026
b7c58ad
added RpcKind + better docs
Jun 18, 2026
fbccc22
query_handle
Jun 19, 2026
2c85b3b
send_and_get_handle
Jun 19, 2026
1a27c1f
refactored query_handle a bit
Jun 19, 2026
077f55b
refactorrr
Jun 21, 2026
e235c6a
k2_rpc_get_response_size() and k2_rpc_fetch_response() now return `EA…
Jun 21, 2026
05a12bb
[EXPERIMENTAL] removed ignore_answer_coroutine
Jun 23, 2026
c5cd6d8
regularize_extra_headers
Jun 26, 2026
221d72b
added query_handle::wait_for_response
Jun 29, 2026
e33d1d3
fixed zeroing query_handle in rpc_queue_push(..)
Jul 2, 2026
1c87c96
insert ignore_answer requests to rpc_query_handles
Jul 15, 2026
a3580a6
issues
Jul 17, 2026
9871fac
fmt
Jul 17, 2026
ffa0464
fmt
Jul 17, 2026
4912295
refactored kphp::rpc::query_handle
Jul 21, 2026
eb0eef1
removed rpc-query-handle.cpp
Jul 21, 2026
3ff1941
fixed nullptr request_buffer, fixed <=0 timeout handling, error becam…
Jul 21, 2026
9d68e3b
query_handle: response type now std::span<std::byte>
Jul 21, 2026
5d024c6
time utils fixes
Jul 22, 2026
454d823
fmt
Jul 22, 2026
bd1beee
fmt
Jul 22, 2026
c28df22
query_handle -> query; removed error description for query::get_respo…
Jul 22, 2026
e8b1ed5
kphp::rpc::query::get_ready_response() takes templated response_alloc…
Jul 22, 2026
e2a6054
TODO
Jul 22, 2026
c320547
ResponseAllocator and ResponseDeleter
Jul 23, 2026
da35b34
ResponseBufferProvider; removed query::wait_for_response; returned re…
Jul 24, 2026
b54ba6f
request_buffer is allocated for requests more than `StringLibContext:…
Jul 24, 2026
42e39b4
fmt
Jul 24, 2026
675aa94
fmt
Jul 24, 2026
8bc0fb6
fmt
Jul 24, 2026
bcbf91b
k2_rpc_fetch_response may return `ENOBUFS`
Jul 24, 2026
48494f2
fixed issues
Jul 28, 2026
861a27c
better docs
Jul 28, 2026
79a0375
removed extra includes and comments
Jul 31, 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
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 != 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
42 changes: 42 additions & 0 deletions runtime-light/k2-platform/k2-header.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,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 @@ -317,6 +321,44 @@ 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.
*
* @return return `0` on success. libc-like `errno` otherwise.
*
* Possible `errno` values:
* `EAI_MEMORY` => max descriptors count achieved.
* `EINVAL` => invalid `actor_name` or request, or connection pool is empty for this actor.
*/
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
Expand Down
22 changes: 0 additions & 22 deletions runtime-light/state/instance-state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include "runtime-common/core/std/containers.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
Loading
Loading