Skip to content

Commit bd85b67

Browse files
committed
fix: proactor_threads is respected in k8s
1 parent 2795c35 commit bd85b67

2 files changed

Lines changed: 75 additions & 0 deletions

File tree

src/server/dfly_main.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ ABSL_DECLARE_FLAG(uint32_t, memcached_port);
8282
ABSL_DECLARE_FLAG(uint16_t, admin_port);
8383
ABSL_DECLARE_FLAG(std::string, admin_bind);
8484
ABSL_DECLARE_FLAG(strings::MemoryBytesFlag, maxmemory);
85+
ABSL_DECLARE_FLAG(uint32_t, proactor_threads);
8586

8687
ABSL_FLAG(string, bind, "",
8788
"Bind address. If empty - binds on all interfaces. "
@@ -1080,6 +1081,12 @@ Usage: dragonfly [FLAGS]
10801081

10811082
#ifdef __linux__
10821083
UpdateResourceLimitsIfInsideContainer(&mem_info, &max_available_threads);
1084+
// If --proactor_threads (or DFLY_proactor_threads env var) was explicitly set by the user,
1085+
// honor it over the cgroup-derived CPU limit. The flag defaults to 0, so any non-zero value
1086+
// means the user explicitly requested a specific thread count.
1087+
if (absl::GetFlag(FLAGS_proactor_threads) > 0) {
1088+
max_available_threads = 0; // causes ProactorPool to use FLAGS_proactor_threads
1089+
}
10831090
#endif
10841091

10851092
if (mem_info.swap_total != 0)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
"""
2+
Tests that --proactor_threads is respected even inside containers with CPU limits.
3+
4+
Background: UpdateResourceLimitsIfInsideContainer() reads the cgroup CPU quota and
5+
passes it as pool_size to ProactorPool. When pool_size != 0, helio's ProactorPool
6+
ignores FLAGS_proactor_threads entirely. The fix resets pool_size to 0 when
7+
--proactor_threads (or DFLY_proactor_threads) is explicitly set, so the flag wins.
8+
"""
9+
10+
import pytest
11+
from .instance import DflyInstanceFactory
12+
13+
14+
@pytest.mark.asyncio
15+
async def test_proactor_threads_flag_is_respected(df_factory: DflyInstanceFactory):
16+
"""Starting with --proactor_threads=N must result in exactly N threads."""
17+
server = df_factory.create(proactor_threads=3)
18+
server.start()
19+
client = server.client()
20+
try:
21+
info = await client.info("server")
22+
assert int(info["thread_count"]) == 3
23+
finally:
24+
await client.aclose()
25+
server.stop()
26+
27+
28+
@pytest.mark.asyncio
29+
async def test_proactor_threads_env_var_is_respected(
30+
df_factory: DflyInstanceFactory, monkeypatch
31+
):
32+
"""DFLY_proactor_threads env var must behave identically to the CLI flag.
33+
34+
The subprocess inherits the parent environment, so setting the variable here
35+
is equivalent to setting it in a Kubernetes pod's env: section.
36+
"""
37+
monkeypatch.setenv("DFLY_proactor_threads", "2")
38+
# No proactor_threads kwarg — only the env var should drive the thread count.
39+
server = df_factory.create()
40+
server.start()
41+
client = server.client()
42+
try:
43+
info = await client.info("server")
44+
assert int(info["thread_count"]) == 2
45+
finally:
46+
await client.aclose()
47+
server.stop()
48+
49+
50+
@pytest.mark.asyncio
51+
async def test_proactor_threads_flag_overrides_env_var(
52+
df_factory: DflyInstanceFactory, monkeypatch
53+
):
54+
"""CLI flag takes priority over DFLY_proactor_threads env var.
55+
56+
ParseFlagsFromEnv() skips env vars when the flag was already set on the
57+
command line (WasPresentOnCommandLine check), so the CLI value must win.
58+
"""
59+
monkeypatch.setenv("DFLY_proactor_threads", "2")
60+
server = df_factory.create(proactor_threads=4)
61+
server.start()
62+
client = server.client()
63+
try:
64+
info = await client.info("server")
65+
assert int(info["thread_count"]) == 4
66+
finally:
67+
await client.aclose()
68+
server.stop()

0 commit comments

Comments
 (0)