PHP
Ajax
Concurrent Requests
Web Development
Asynchronous Programming

PHP Multiple Ajax requests First request block second request

Interview Questions practice on Codemia

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

Browse interview questions

Introduction

If two AJAX calls hit the same PHP application and the second one appears to wait for the first, the browser is usually not the real problem. In many cases PHP is serializing those requests because the session is locked for the lifetime of the first request.

Why This Happens

By default, PHP stores session data in files. When a request calls session_start(), PHP opens the session storage and places an exclusive lock on it. That lock is kept until the script ends or until the session is explicitly closed.

If a second request from the same user arrives while the first request still holds the lock, the second request cannot read or write $_SESSION yet. It waits, which makes the two AJAX requests look sequential even though the browser sent them concurrently.

This is easy to reproduce with a slow endpoint:

php
1<?php
2session_start();
3
4$_SESSION['last_action'] = 'report';
5sleep(5);
6
7header('Content-Type: application/json');
8echo json_encode(['status' => 'done']);

If another request from the same browser session also calls session_start(), it will often pause until the five-second sleep finishes.

Release The Session Early

The standard fix is to close the session as soon as you no longer need it. Read the values you need, write any updates, and then call session_write_close().

php
1<?php
2session_start();
3
4$userId = $_SESSION['user_id'] ?? null;
5$_SESSION['last_action'] = 'report';
6session_write_close();
7
8sleep(5);
9
10header('Content-Type: application/json');
11echo json_encode([
12    'userId' => $userId,
13    'status' => 'done'
14]);

Now the session lock is released before the expensive work starts, so a second request can continue immediately.

This pattern is especially useful for endpoints that:

  • check whether a user is logged in
  • read a small amount of session state
  • perform long database or API work afterward

The Browser Is Usually Not The Bottleneck

Modern browsers can send multiple requests to the same origin. A simple frontend example proves that the client is willing to do work in parallel:

javascript
1async function loadData() {
2  const first = fetch("/api/report.php");
3  const second = fetch("/api/notifications.php");
4
5  const results = await Promise.all([first, second]);
6  console.log(results.map((response) => response.status));
7}
8
9loadData();

If one PHP endpoint blocks the other, the cause is typically server-side state management, not fetch() itself.

When To Avoid Sessions Entirely

Some endpoints do not need session data at all. For those routes, do not call session_start(). If the request only needs a bearer token, API key, signed cookie, or request payload, keeping it stateless avoids unnecessary locking and makes horizontal scaling easier.

A useful rule is:

  • use sessions for small authentication or preference data
  • avoid sessions for long-running background-like requests
  • do not hold the session open while waiting on I/O

Other Sources Of Apparent Blocking

Session locking is the most common reason, but not the only one.

Single-threaded development servers can also serialize requests. A file lock, database row lock, or external API rate limit can create the same symptom. That is why it helps to inspect timing in server logs instead of assuming the session is always the cause.

For example, if both requests are hitting different PHP-FPM workers but still waiting, look for shared resources:

php
1<?php
2$start = microtime(true);
3error_log('request started: ' . $start);
4
5// expensive work here
6
7$end = microtime(true);
8error_log('request finished in ' . ($end - $start));

With logs from multiple endpoints, you can see whether the second request started immediately or only after the first released some shared lock.

Common Pitfalls

  • Calling session_write_close() too late. If you put it after a slow query or sleep(), the second request still waits.
  • Reopening the session accidentally. Libraries or included files may call session_start() again and recreate the lock.
  • Assuming every concurrent issue is a browser problem. Test the backend timing before changing frontend code.
  • Using sessions for large mutable state. The more often requests need to update $_SESSION, the more often you serialize user traffic.

Summary

  • PHP sessions commonly block concurrent AJAX requests from the same user.
  • The lock starts at session_start() and lasts until the session is closed or the request ends.
  • Call session_write_close() as soon as session access is finished.
  • Skip sessions completely for endpoints that do not need them.
  • If the issue remains, investigate other shared locks such as files, databases, or a single-threaded dev server.

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.