1
+ <?php
2
+ require_once 'vendor/autoload.php ' ;
3
+
4
+ use Rcalicdan \FiberAsync \EventLoop \EventLoop ;
5
+
6
+ // Start output buffering to control response timing
7
+ ob_start ();
8
+ ?>
9
+ <!DOCTYPE html>
10
+ <html lang="en">
11
+
12
+ <head>
13
+ <meta charset="UTF-8">
14
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
15
+ <title>Web Defer Test</title>
16
+ <style>
17
+ body {
18
+ font-family: Arial, sans-serif;
19
+ max-width: 800px;
20
+ margin: 0 auto;
21
+ padding: 20px;
22
+ background-color: #f5f5f5;
23
+ }
24
+
25
+ .container {
26
+ background: white;
27
+ padding: 20px;
28
+ border-radius: 8px;
29
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
30
+ }
31
+
32
+ .status {
33
+ padding: 10px;
34
+ border-radius: 4px;
35
+ margin: 10px 0;
36
+ }
37
+
38
+ .success {
39
+ background-color: #d4edda;
40
+ color: #155724;
41
+ }
42
+
43
+ .info {
44
+ background-color: #d1ecf1;
45
+ color: #0c5460;
46
+ }
47
+
48
+ .warning {
49
+ background-color: #fff3cd;
50
+ color: #856404;
51
+ }
52
+
53
+ button {
54
+ background-color: #007bff;
55
+ color: white;
56
+ padding: 10px 20px;
57
+ border: none;
58
+ border-radius: 4px;
59
+ cursor: pointer;
60
+ margin: 5px;
61
+ }
62
+
63
+ button:hover {
64
+ background-color: #0056b3;
65
+ }
66
+
67
+ .log-box {
68
+ background-color: #f8f9fa;
69
+ border: 1px solid #dee2e6;
70
+ border-radius: 4px;
71
+ padding: 15px;
72
+ font-family: monospace;
73
+ max-height: 400px;
74
+ overflow-y: auto;
75
+ white-space: pre-wrap;
76
+ }
77
+
78
+ .form-group {
79
+ margin-bottom: 15px;
80
+ }
81
+
82
+ label {
83
+ display: block;
84
+ margin-bottom: 5px;
85
+ font-weight: bold;
86
+ }
87
+
88
+ input,
89
+ textarea,
90
+ select {
91
+ width: 100%;
92
+ padding: 8px;
93
+ border: 1px solid #ddd;
94
+ border-radius: 4px;
95
+ box-sizing: border-box;
96
+ }
97
+ </style>
98
+ </head>
99
+
100
+ <body>
101
+ <div class="container">
102
+ <h1>🌐 Web Defer Functionality Test</h1>
103
+
104
+ <?php if (empty ($ _POST )): ?>
105
+ <!-- Test Selection Form -->
106
+ <div class="status info">
107
+ <strong>📋 Select a test to run:</strong><br>
108
+ These tests simulate background tasks and demonstrate defer cleanup in web context.
109
+ </div>
110
+
111
+ <form method="POST">
112
+ <div class="form-group">
113
+ <label for="test_type">Test Type:</label>
114
+ <select name="test_type" id="test_type">
115
+ <option value="email">📧 Background Email Processing</option>
116
+ <option value="file">📁 File Processing with Cleanup</option>
117
+ <option value="api">🌍 API Calls with Retry Queue</option>
118
+ <option value="session">👤 User Session Logging</option>
119
+ </select>
120
+ </div>
121
+
122
+ <div class="form-group">
123
+ <label for="duration">Processing Duration (seconds):</label>
124
+ <input type="number" name="duration" id="duration" value="5" min="1" max="30">
125
+ <small>How long the background task should run</small>
126
+ </div>
127
+
128
+ <div class="form-group">
129
+ <label for="early_exit">Simulate Early Exit:</label>
130
+ <select name="early_exit" id="early_exit">
131
+ <option value="no">No - Let task complete normally</option>
132
+ <option value="yes">Yes - Terminate early to test defer cleanup</option>
133
+ </select>
134
+ </div>
135
+
136
+ <button type="submit">🚀 Run Test</button>
137
+ </form>
138
+
139
+ <!-- Show existing log files -->
140
+ <div style="margin-top: 30px;">
141
+ <h3>📂 Previous Test Results:</h3>
142
+ <?php
143
+ $ logFiles = glob ("web_test_*.log " );
144
+ $ jsonFiles = glob ("web_*_queue*.json " );
145
+
146
+ if (empty ($ logFiles ) && empty ($ jsonFiles )) {
147
+ echo '<div class="status info">No previous test results found.</div> ' ;
148
+ } else {
149
+ echo '<div class="log-box"> ' ;
150
+ foreach (array_merge ($ logFiles , $ jsonFiles ) as $ file ) {
151
+ $ size = filesize ($ file );
152
+ $ time = date ('Y-m-d H:i:s ' , filemtime ($ file ));
153
+ echo "📄 <a href='view_log.php?file= " . urlencode ($ file ) . "' target='_blank'> {$ file }</a> ( {$ size } bytes, {$ time }) \n" ;
154
+ }
155
+ echo '</div> ' ;
156
+ }
157
+ ?>
158
+ </div>
159
+
160
+ <?php else :
161
+ // Process the test
162
+ $ testType = $ _POST ['test_type ' ] ?? 'email ' ;
163
+ $ duration = (int )($ _POST ['duration ' ] ?? 5 );
164
+ $ earlyExit = $ _POST ['early_exit ' ] === 'yes ' ;
165
+
166
+ $ testId = uniqid ();
167
+ $ logFile = "web_test_ {$ testType }_ {$ testId }.log " ;
168
+
169
+ // Set up defer cleanup for web context
170
+ process_defer (function () use ($ testType , $ testId , $ logFile ) {
171
+ $ timestamp = date ('Y-m-d H:i:s ' );
172
+ $ logEntry = "[ {$ timestamp }] 🧹 WEB DEFER CLEANUP EXECUTED \n" ;
173
+ $ logEntry .= "[ {$ timestamp }] Test Type: {$ testType }\n" ;
174
+ $ logEntry .= "[ {$ timestamp }] Test ID: {$ testId }\n" ;
175
+ $ logEntry .= "[ {$ timestamp }] Cleanup completed after response sent to user \n" ;
176
+
177
+ file_put_contents ($ logFile , $ logEntry , FILE_APPEND | LOCK_EX );
178
+
179
+ // Also log to error log for verification
180
+ error_log ("Web defer cleanup executed for test: {$ testType }_ {$ testId }" );
181
+ });
182
+
183
+ echo "<div class='status success'>✅ <strong>Test Started:</strong> {$ testType } (ID: {$ testId })</div> " ;
184
+ echo "<div class='status info'>📊 <strong>Parameters:</strong> Duration: {$ duration }s, Early Exit: " . ($ earlyExit ? 'Yes ' : 'No ' ) . "</div> " ;
185
+
186
+ // Start the background task
187
+ async (function () use ($ testType , $ duration , $ earlyExit , $ testId , $ logFile ) {
188
+ $ startTime = time ();
189
+ $ logEntry = "[ " . date ('Y-m-d H:i:s ' ) . "] 🚀 Background task started: {$ testType }\n" ;
190
+ file_put_contents ($ logFile , $ logEntry , FILE_APPEND | LOCK_EX );
191
+
192
+ for ($ i = 1 ; $ i <= $ duration ; $ i ++) {
193
+ $ logEntry = "[ " . date ('Y-m-d H:i:s ' ) . "] Processing step {$ i }/ {$ duration }\n" ;
194
+ file_put_contents ($ logFile , $ logEntry , FILE_APPEND | LOCK_EX );
195
+
196
+ switch ($ testType ) {
197
+ case 'email ' :
198
+ $ logEntry = "[ " . date ('Y-m-d H:i:s ' ) . "] 📧 Sending email batch {$ i }\n" ;
199
+ break ;
200
+ case 'file ' :
201
+ $ logEntry = "[ " . date ('Y-m-d H:i:s ' ) . "] 📁 Processing file batch {$ i }\n" ;
202
+ break ;
203
+ case 'api ' :
204
+ $ logEntry = "[ " . date ('Y-m-d H:i:s ' ) . "] 🌍 Making API call {$ i }\n" ;
205
+ break ;
206
+ case 'session ' :
207
+ $ logEntry = "[ " . date ('Y-m-d H:i:s ' ) . "] 👤 Logging user activity {$ i }\n" ;
208
+ break ;
209
+ }
210
+
211
+ file_put_contents ($ logFile , $ logEntry , FILE_APPEND | LOCK_EX );
212
+ await (delay (1 ));
213
+
214
+ // Simulate early exit
215
+ if ($ earlyExit && $ i >= 2 ) {
216
+ $ logEntry = "[ " . date ('Y-m-d H:i:s ' ) . "] ⚠️ Simulating early exit at step {$ i }\n" ;
217
+ file_put_contents ($ logFile , $ logEntry , FILE_APPEND | LOCK_EX );
218
+
219
+ // Create unfinished work queue
220
+ $ unfinishedWork = [];
221
+ for ($ j = $ i + 1 ; $ j <= $ duration ; $ j ++) {
222
+ $ unfinishedWork [] = [
223
+ 'step ' => $ j ,
224
+ 'type ' => $ testType ,
225
+ 'status ' => 'pending ' ,
226
+ 'created_at ' => date ('Y-m-d H:i:s ' )
227
+ ];
228
+ }
229
+
230
+ if (!empty ($ unfinishedWork )) {
231
+ $ queueFile = "web_ {$ testType }_queue_ {$ testId }.json " ;
232
+ file_put_contents ($ queueFile , json_encode ($ unfinishedWork , JSON_PRETTY_PRINT ));
233
+ $ logEntry = "[ " . date ('Y-m-d H:i:s ' ) . "] 💾 Saved " . count ($ unfinishedWork ) . " unfinished tasks to {$ queueFile }\n" ;
234
+ file_put_contents ($ logFile , $ logEntry , FILE_APPEND | LOCK_EX );
235
+ }
236
+
237
+ exit (0 ); // Force early exit to test defer
238
+ }
239
+ }
240
+
241
+ $ logEntry = "[ " . date ('Y-m-d H:i:s ' ) . "] ✅ Background task completed successfully \n" ;
242
+ file_put_contents ($ logFile , $ logEntry , FILE_APPEND | LOCK_EX );
243
+ });
244
+ ?>
245
+
246
+ <div class="status warning">
247
+ ⏳ <strong>Background task is running...</strong><br>
248
+ The task will continue processing in the background even after this page loads.
249
+ Check the log files below to see the results.
250
+ </div>
251
+
252
+ <div class="status info">
253
+ 📋 <strong>What's happening:</strong><br>
254
+ 1. This response is sent to your browser immediately<br>
255
+ 2. Background task continues processing for <?= $ duration ?> seconds<br>
256
+ <?php if ($ earlyExit ): ?>
257
+ 3. Task will exit early around step 2 to test defer cleanup<br>
258
+ 4. Defer cleanup will execute after early exit<br>
259
+ <?php else : ?>
260
+ 3. Task will complete all <?= $ duration ?> steps<br>
261
+ 4. Defer cleanup will execute after task completion<br>
262
+ <?php endif ; ?>
263
+ 5. All activity is logged to: <strong><?= $ logFile ?> </strong>
264
+ </div>
265
+
266
+ <div style="margin-top: 20px;">
267
+ <button onclick="window.location.reload()">🔄 Run Another Test</button>
268
+ <button onclick="location.href='view_log.php?file=<?= urlencode ($ logFile ) ?> '">📄 View Log File</button>
269
+ <button onclick="location.href='web_defer_test.php'">🏠 Back to Home</button>
270
+ </div>
271
+
272
+ <script>
273
+ // Auto-refresh log file link after a few seconds
274
+ setTimeout(function() {
275
+ console.log('Background task should be running...');
276
+ }, 2000);
277
+ </script>
278
+ <?php endif ; ?>
279
+ </div>
280
+ </body>
281
+
282
+ </html>
283
+
284
+ <?php
285
+ // Send response to user immediately, but keep PHP running for background tasks
286
+ if (!empty ($ _POST )) {
287
+ // Flush output to user
288
+ $ output = ob_get_contents ();
289
+ ob_end_clean ();
290
+
291
+ echo $ output ;
292
+
293
+ // Send response to user immediately
294
+ if (function_exists ('fastcgi_finish_request ' )) {
295
+ fastcgi_finish_request ();
296
+ } else {
297
+ // For non-FastCGI environments
298
+ if (ob_get_level ()) {
299
+ ob_end_flush ();
300
+ }
301
+ flush ();
302
+ }
303
+
304
+ // Now run the event loop for background processing
305
+
306
+ EventLoop::getInstance ()->run ();
307
+ }
308
+ ?>
0 commit comments