Skip to content

Commit 60130d1

Browse files
authored
server: add SSE ping interval (#24013)
1 parent a468b89 commit 60130d1

5 files changed

Lines changed: 29 additions & 8 deletions

File tree

common/arg.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3027,6 +3027,13 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
30273027
params.timeout_write = value;
30283028
}
30293029
).set_examples({LLAMA_EXAMPLE_SERVER}).set_env("LLAMA_ARG_TIMEOUT"));
3030+
add_opt(common_arg(
3031+
{"--sse-ping-interval"}, "N",
3032+
string_format("server SSE ping interval in seconds (-1 = disabled, default: %d)", params.sse_ping_interval),
3033+
[](common_params & params, int value) {
3034+
params.sse_ping_interval = value;
3035+
}
3036+
).set_examples({LLAMA_EXAMPLE_SERVER}).set_env("LLAMA_ARG_SSE_PING_INTERVAL"));
30303037
add_opt(common_arg(
30313038
{"--threads-http"}, "N",
30323039
string_format("number of threads used to process HTTP requests (default: %d)", params.n_threads_http),

common/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@ struct common_params {
592592
bool reuse_port = false; // allow multiple sockets to bind to the same port
593593
int32_t timeout_read = 3600; // http read timeout in seconds
594594
int32_t timeout_write = timeout_read; // http write timeout in seconds
595+
int32_t sse_ping_interval = 30; // SSE ping interval in seconds
595596
int32_t n_threads_http = -1; // number of threads to process HTTP requests (TODO: support threadpool)
596597
int32_t n_cache_reuse = 0; // min chunk size to reuse from the cache via KV shifting
597598
bool cache_prompt = true; // whether to enable prompt caching

tools/server/server-context.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3693,6 +3693,7 @@ std::unique_ptr<server_res_generator> server_routes::handle_completions_impl(
36933693
auto res = create_response();
36943694
auto completion_id = gen_chatcmplid();
36953695
auto & rd = res->rd;
3696+
auto & params = this->params;
36963697

36973698
try {
36983699
std::vector<server_task> tasks;
@@ -3828,7 +3829,7 @@ std::unique_ptr<server_res_generator> server_routes::handle_completions_impl(
38283829
}
38293830
res->status = 200;
38303831
res->content_type = "text/event-stream";
3831-
res->next = [res_this = res.get(), res_type, &req](std::string & output) -> bool {
3832+
res->next = [res_this = res.get(), res_type, &req, &params](std::string & output) -> bool {
38323833
static auto format_error = [](task_response_type res_type, const json & res_json) {
38333834
if (res_type == TASK_RESPONSE_TYPE_ANTHROPIC) {
38343835
return format_anthropic_sse({
@@ -3873,7 +3874,25 @@ std::unique_ptr<server_res_generator> server_routes::handle_completions_impl(
38733874
}
38743875

38753876
// receive subsequent results
3876-
auto result = rd.next(req.should_stop);
3877+
bool timeout = false;
3878+
int64_t start_time = ggml_time_ms();
3879+
auto result = rd.next([&timeout, &req, &start_time, &params]() {
3880+
if (req.should_stop()) {
3881+
return true; // should_stop condition met
3882+
} else if (params.sse_ping_interval > 0 && ggml_time_ms() - start_time > (int64_t)params.sse_ping_interval * 1000) {
3883+
timeout = true;
3884+
return true; // timeout
3885+
}
3886+
return false;
3887+
});
3888+
3889+
if (timeout) {
3890+
// some clients may time out (e.g. undici) will time out if no data is received for a while, so we need to send a ping to keep the connection alive
3891+
SRV_DBG("%s", "sending SSE ping\n");
3892+
output = ":\n\n";
3893+
return true;
3894+
}
3895+
38773896
if (result == nullptr) {
38783897
SRV_DBG("%s", "stopping streaming due to should_stop condition\n");
38793898
GGML_ASSERT(req.should_stop());

tools/server/server-queue.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -381,10 +381,6 @@ server_task_result_ptr server_response_reader::next(const std::function<bool()>
381381
if (result == nullptr) {
382382
// timeout, check stop condition
383383
if (should_stop()) {
384-
const int64_t time_elapsed_ms = ggml_time_ms() - time_start_ms;
385-
if (time_elapsed_ms > 30000) {
386-
SRV_WRN("%s", "request cancelled after 30s, potentially a client-side timeout; please check your client's code\n");
387-
}
388384
return nullptr;
389385
}
390386
} else {

tools/server/server-queue.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,6 @@ struct server_response_reader {
169169
bool cancelled = false;
170170
int polling_interval_seconds;
171171

172-
const int64_t time_start_ms = ggml_time_ms();
173-
174172
// tracking generation state and partial tool calls
175173
// only used by streaming completions
176174
std::vector<task_result_state> states;

0 commit comments

Comments
 (0)