PHP
Asynchronous
Windows
Task Notification
Programming

How to notify user when async task ends in PHP/ Windows

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

When a PHP application starts a long-running task, the hard part is usually not the background work itself. The harder problem is telling the user that the work finished, especially on Windows where many examples assume Unix process tools that do not exist.

Separate the Job from the Notification

In a web application, the browser and the PHP worker do not share a live connection by default. That means the reliable pattern is:

  1. Start a background job and return a job ID.
  2. Store status somewhere shared, such as a file, database row, or Redis key.
  3. Let the browser poll or subscribe for status updates.

The Windows operating system matters when starting the worker process, but the notification usually belongs in the browser, not the server console.

Starting a Background Task on Windows

One simple Windows-friendly approach is to launch a second PHP process with start /B. The main request returns immediately while the worker updates a status file.

php
1<?php
2// start_job.php
3$jobId = bin2hex(random_bytes(8));
4$statusFile = __DIR__ . "/jobs/$jobId.json";
5
6file_put_contents($statusFile, json_encode([
7    "status" => "queued",
8    "message" => "Job created"
9]));
10
11$php = escapeshellarg(PHP_BINARY);
12$worker = escapeshellarg(__DIR__ . "/worker.php");
13$jobArg = escapeshellarg($jobId);
14
15$command = "start /B \"job-$jobId\" $php $worker $jobArg";
16pclose(popen($command, "r"));
17
18header("Content-Type: application/json");
19echo json_encode(["jobId" => $jobId]);

The worker script does the actual work and updates shared status.

php
1<?php
2// worker.php
3$jobId = $argv[1];
4$statusFile = __DIR__ . "/jobs/$jobId.json";
5
6file_put_contents($statusFile, json_encode([
7    "status" => "running",
8    "message" => "Processing started"
9]));
10
11sleep(8);
12
13file_put_contents($statusFile, json_encode([
14    "status" => "completed",
15    "message" => "Report is ready"
16]));

This is not a full job queue, but it demonstrates the essential pattern clearly.

Exposing Job Status to the Browser

The client needs a lightweight endpoint that reads the shared status store.

php
1<?php
2// job_status.php
3$jobId = $_GET["jobId"] ?? "";
4$statusFile = __DIR__ . "/jobs/$jobId.json";
5
6header("Content-Type: application/json");
7
8if (!is_file($statusFile)) {
9    http_response_code(404);
10    echo json_encode(["error" => "Unknown job"]);
11    exit;
12}
13
14echo file_get_contents($statusFile);

The browser can poll this endpoint every few seconds.

html
1<script>
2async function waitForJob(jobId) {
3  const statusLabel = document.getElementById("status");
4
5  const timer = setInterval(async () => {
6    const response = await fetch(`/job_status.php?jobId=${jobId}`);
7    const data = await response.json();
8
9    statusLabel.textContent = data.message;
10
11    if (data.status === "completed") {
12      clearInterval(timer);
13      alert("Background task finished.");
14    }
15  }, 2000);
16}
17</script>

Polling is often enough for admin tools, report generation, imports, and one-off exports. It is easy to deploy and works well with ordinary PHP hosting.

When to Use Something Stronger

If jobs are frequent or critical, add infrastructure instead of stretching plain PHP scripts too far. A database-backed queue, Redis queue, or Windows service gives better durability and monitoring. If the user needs real-time updates without polling, use WebSockets or Server-Sent Events through an application stack that supports persistent connections.

The key design decision is to treat notification as a state change the client can observe. Once that is in place, the transport can evolve without changing the core workflow.

Common Pitfalls

  • Trying to push a message directly from a finished PHP worker into an already completed HTTP response. The browser cannot receive data from a closed request.
  • Using Unix-specific background process commands on Windows. nohup and shell syntax from Linux examples do not translate cleanly.
  • Keeping status only in memory. A second request cannot read in-memory state from a previous PHP process.
  • Polling too aggressively. A one or two second interval is usually enough and avoids unnecessary server load.
  • Skipping failure states. Store failed and an error message, not only completed, or users will not know why the job disappeared.

Summary

  • On Windows, PHP can start a background worker with start /B.
  • The robust pattern is job ID plus shared status storage plus client polling.
  • Browser notification usually belongs in JavaScript, not the PHP worker itself.
  • Status endpoints should return queued, running, completed, and failed states.
  • If throughput grows, move from ad hoc scripts to a proper queue or real-time transport.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.