33namespace Doppar \Queue ;
44
55use Doppar \Queue \Models \QueueJob ;
6+ use Doppar \Queue \Exceptions \JobTimeoutException ;
67use Doppar \Queue \Contracts \JobInterface ;
78
89class QueueWorker
@@ -187,8 +188,8 @@ protected function processJob(QueueJob $queueJob): void
187188 ($ this ->onJobProcessing )($ job );
188189 }
189190
190- // Execute the job
191- $ this ->executeJob ($ job );
191+ // Execute the job with timeout
192+ $ this ->executeJobWithTimeout ($ job );
192193
193194 // Delete the job from queue if successful
194195 $ this ->manager ->delete ($ queueJob );
@@ -202,6 +203,47 @@ protected function processJob(QueueJob $queueJob): void
202203 }
203204 }
204205
206+ /**
207+ * Execute a job with timeout protection.
208+ *
209+ * @param JobInterface $job
210+ * @return void
211+ * @throws \Throwable
212+ */
213+ protected function executeJobWithTimeout (JobInterface $ job ): void
214+ {
215+ $ timeout = $ job ->getTimeout ();
216+
217+ if ($ timeout === null || !extension_loaded ('pcntl ' )) {
218+ // No timeout or pcntl not available, execute normally
219+ $ this ->executeJob ($ job );
220+ return ;
221+ }
222+
223+ // Set up timeout handler
224+ $ timedOut = false ;
225+
226+ pcntl_signal (SIGALRM , function () use (&$ timedOut ) {
227+ $ timedOut = true ;
228+ });
229+
230+ pcntl_alarm ($ timeout );
231+
232+ try {
233+ $ this ->executeJob ($ job );
234+ pcntl_alarm (0 );
235+ } catch (\Throwable $ e ) {
236+ pcntl_alarm (0 );
237+ throw $ e ;
238+ }
239+
240+ if ($ timedOut ) {
241+ throw new JobTimeoutException (
242+ "Job exceeded maximum execution time of {$ timeout } seconds "
243+ );
244+ }
245+ }
246+
205247 /**
206248 * Execute a job.
207249 *
0 commit comments