Skip to content

Commit 3f6682b

Browse files
authored
Call reseed in fork process (#108)
* Call reseed in fork process * update
1 parent 56962da commit 3f6682b

File tree

5 files changed

+13
-45
lines changed

5 files changed

+13
-45
lines changed

README.md

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -70,24 +70,6 @@ in comparison with the `uuid_utils` default behaviour, but is still faster than
7070
UUID('ffe95fcc-b818-4aca-a350-e0a35b9de6ec')
7171
```
7272

73-
## Fork processes
74-
75-
The underlying Rust library for generating random values is not guaranteed to reseed when you fork the process. This would mean that after forking, the `uuid_utils` calls can return the same value for a few calls, and then it reseeds.
76-
77-
If you plan to use this library alongside forking you will want to explicitly reseed post-fork. You can do this with:
78-
79-
```py
80-
import os
81-
82-
import uuid_utils
83-
84-
# Calling it manually when forking
85-
uuid_utils.reseed_rng()
86-
87-
# Or registering it to be called when forking
88-
os.register_at_fork(uuid_utils.reseed_rng)
89-
```
90-
9173
## Benchmarks
9274

9375
| Benchmark | Min | Max | Mean | Min (+) | Max (+) | Mean (+) |

docs/index.md

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -76,24 +76,6 @@ in comparison with the `uuid_utils` default behaviour, but is still faster than
7676
UUID('ffe95fcc-b818-4aca-a350-e0a35b9de6ec')
7777
```
7878

79-
## Fork processes
80-
81-
The underlying Rust library for generating random values is not guaranteed to reseed when you fork the process. This would mean that after forking, the `uuid_utils` calls can return the same value for a few calls, and then it reseeds.
82-
83-
If you plan to use this library alongside forking you will want to explicitly reseed post-fork. You can do this with:
84-
85-
```py
86-
import os
87-
88-
import uuid_utils
89-
90-
# Calling it manually when forking
91-
uuid_utils.reseed_rng()
92-
93-
# Or registering it to be called when forking
94-
os.register_at_fork(uuid_utils.reseed_rng)
95-
```
96-
9779
## Benchmarks
9880

9981
| Benchmark | Min | Max | Mean | Min (+) | Max (+) | Mean (+) |

python/uuid_utils/__init__.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
from uuid import SafeUUID
23

34
from ._uuid_utils import (
@@ -14,7 +15,6 @@
1415
UUID,
1516
__version__,
1617
getnode,
17-
reseed_rng,
1818
uuid1,
1919
uuid3,
2020
uuid4,
@@ -23,6 +23,14 @@
2323
uuid7,
2424
uuid8,
2525
)
26+
from ._uuid_utils import (
27+
reseed as reseed_rng,
28+
)
29+
30+
# Reseed the RNG in the child process after a fork.
31+
# Otherwise both parent and child processes may generate the same UUIDs for some time.
32+
if hasattr(os, "fork"):
33+
os.register_at_fork(after_in_child=reseed_rng)
2634

2735
__all__ = [
2836
"MAX",

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ fn getnode() -> PyResult<u64> {
427427
}
428428

429429
#[pyfunction]
430-
fn reseed_rng() -> PyResult<()> {
430+
fn reseed() -> PyResult<()> {
431431
rand::rng()
432432
.reseed()
433433
.map_err(|err| PyOSError::new_err(err.to_string()))
@@ -457,7 +457,7 @@ fn _uuid_utils(m: &Bound<'_, PyModule>) -> PyResult<()> {
457457
m.add_function(wrap_pyfunction!(uuid7, m)?)?;
458458
m.add_function(wrap_pyfunction!(uuid8, m)?)?;
459459
m.add_function(wrap_pyfunction!(getnode, m)?)?;
460-
m.add_function(wrap_pyfunction!(reseed_rng, m)?)?;
460+
m.add_function(wrap_pyfunction!(reseed, m)?)?;
461461
m.add("NAMESPACE_DNS", UUID::NAMESPACE_DNS)?;
462462
m.add("NAMESPACE_URL", UUID::NAMESPACE_URL)?;
463463
m.add("NAMESPACE_OID", UUID::NAMESPACE_OID)?;

tests/test_uuid.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -208,16 +208,13 @@ def test_getnode() -> None:
208208

209209

210210
@pytest.mark.skipif(sys.platform == "win32", reason="Does not run on Windows")
211-
def test_reseed_rng_with_fork() -> None:
211+
def test_reseed_is_called_when_forking() -> None:
212212
read_end, write_end = os.pipe()
213-
# forcibly generate uuid before fork to have rng state
214213
uuid_utils.uuid4()
215214

216-
pid = os.fork() # type: ignore[attr-defined]
215+
pid = os.fork()
217216
if pid == 0:
218217
os.close(read_end)
219-
# explicity reseed in the child
220-
uuid_utils.reseed_rng()
221218
next_uuid_child = str(uuid_utils.uuid4())
222219
with os.fdopen(write_end, "w") as write_pipe:
223220
write_pipe.write(next_uuid_child)
@@ -229,7 +226,6 @@ def test_reseed_rng_with_fork() -> None:
229226
with os.fdopen(read_end) as read_pipe:
230227
uuid_from_pipe = uuid_utils.UUID(read_pipe.read())
231228

232-
# the uuids should be different because we reseeded
233229
assert next_parent_uuid != uuid_from_pipe
234230

235231

0 commit comments

Comments
 (0)