2
2
3
3
namespace Rcalicdan \FiberAsync \EventLoop \Handlers ;
4
4
5
+ use Rcalicdan \FiberAsync \EventLoop \Managers \FiberManager ;
6
+
5
7
/**
6
- * Manages the running state of the event loop.
8
+ * Manages the running state of the event loop with enhanced shutdown capabilities .
7
9
*
8
- * This handler provides simple state management for the event loop,
9
- * allowing it to be started, stopped, and queried for its current state.
10
- * This is essential for controlling the main event loop execution.
10
+ * This handler provides state management for the event loop with the ability
11
+ * to force complete shutdown by clearing all pending work to prevent hanging.
11
12
*/
12
13
final class StateHandler
13
14
{
@@ -16,6 +17,21 @@ final class StateHandler
16
17
*/
17
18
private bool $ running = true ;
18
19
20
+ /**
21
+ * @var bool Whether a forced shutdown has been requested
22
+ */
23
+ private bool $ forceShutdown = false ;
24
+
25
+ /**
26
+ * @var float Timestamp when stop() was called
27
+ */
28
+ private float $ stopRequestTime = 0.0 ;
29
+
30
+ /**
31
+ * @var float Maximum time to wait for graceful shutdown (seconds)
32
+ */
33
+ private float $ gracefulShutdownTimeout = 2.0 ;
34
+
19
35
/**
20
36
* Check if the event loop is currently running.
21
37
*
@@ -27,24 +43,112 @@ public function isRunning(): bool
27
43
}
28
44
29
45
/**
30
- * Stop the event loop.
46
+ * Stop the event loop gracefully .
31
47
*
32
48
* This will cause the main event loop to exit on its next iteration.
33
- * Useful for graceful shutdown or when all work is completed .
49
+ * Records the stop request time for potential forced shutdown .
34
50
*/
35
51
public function stop (): void
52
+ {
53
+ if (!$ this ->running ) {
54
+ return ;
55
+ }
56
+
57
+ $ this ->running = false ;
58
+ $ this ->stopRequestTime = microtime (true );
59
+ }
60
+
61
+ /**
62
+ * Force immediate shutdown of the event loop.
63
+ *
64
+ * This bypasses graceful shutdown and immediately stops the loop.
65
+ * Should be used when graceful shutdown fails or takes too long.
66
+ */
67
+ public function forceStop (): void
36
68
{
37
69
$ this ->running = false ;
70
+ $ this ->forceShutdown = true ;
71
+ }
72
+
73
+ /**
74
+ * Check if a forced shutdown has been requested.
75
+ *
76
+ * @return bool True if force shutdown is active
77
+ */
78
+ public function isForcedShutdown (): bool
79
+ {
80
+ return $ this ->forceShutdown ;
81
+ }
82
+
83
+ /**
84
+ * Check if the graceful shutdown timeout has been exceeded.
85
+ *
86
+ * @return bool True if timeout exceeded and force shutdown should be triggered
87
+ */
88
+ public function shouldForceShutdown (): bool
89
+ {
90
+ if ($ this ->running || $ this ->forceShutdown ) {
91
+ return false ;
92
+ }
93
+
94
+ return (microtime (true ) - $ this ->stopRequestTime ) > $ this ->gracefulShutdownTimeout ;
38
95
}
39
96
40
97
/**
41
98
* Start the event loop.
42
99
*
43
- * This resets the running state to true, allowing the event loop
44
- * to continue processing if it was previously stopped.
100
+ * This resets the running state to true and clears any shutdown flags.
45
101
*/
46
102
public function start (): void
47
103
{
48
104
$ this ->running = true ;
105
+ $ this ->forceShutdown = false ;
106
+ $ this ->stopRequestTime = 0.0 ;
107
+ }
108
+
109
+ /**
110
+ * Set the graceful shutdown timeout.
111
+ *
112
+ * @param float $timeout Timeout in seconds
113
+ */
114
+ public function setGracefulShutdownTimeout (float $ timeout ): void
115
+ {
116
+ $ this ->gracefulShutdownTimeout = max (0.1 , $ timeout );
117
+ }
118
+
119
+ /**
120
+ * Get the current graceful shutdown timeout.
121
+ *
122
+ * @return float Timeout in seconds
123
+ */
124
+ public function getGracefulShutdownTimeout (): float
125
+ {
126
+ return $ this ->gracefulShutdownTimeout ;
127
+ }
128
+
129
+ /**
130
+ * Get the time elapsed since stop() was called.
131
+ *
132
+ * @return float Time in seconds, or 0.0 if stop hasn't been called
133
+ */
134
+ public function getTimeSinceStopRequest (): float
135
+ {
136
+ if ($ this ->stopRequestTime === 0.0 ) {
137
+ return 0.0 ;
138
+ }
139
+
140
+ return microtime (true ) - $ this ->stopRequestTime ;
141
+ }
142
+
143
+ /**
144
+ * Check if we're currently in a graceful shutdown period.
145
+ *
146
+ * @return bool True if stop() was called but timeout hasn't been reached
147
+ */
148
+ public function isInGracefulShutdown (): bool
149
+ {
150
+ return !$ this ->running &&
151
+ !$ this ->forceShutdown &&
152
+ $ this ->stopRequestTime > 0.0 ;
49
153
}
50
- }
154
+ }
0 commit comments