DEV Community

Cover image for Delivery Slot Allocation: Designing a Safe and Concurrent Booking System
Abanoub Kerols
Abanoub Kerols

Posted on

Delivery Slot Allocation: Designing a Safe and Concurrent Booking System


When building an e-commerce, food delivery, logistics, or appointment-booking system, one common problem appears again and again:

How can we allocate a limited resource to multiple customers without overbooking it?

A delivery slot is a perfect example of a shared resource.

Imagine that a delivery slot can handle only 5 orders:

10:00 - 12:00
Capacity: 5
Booked: 4
Enter fullscreen mode Exit fullscreen mode

There is only one remaining position.

If two customers try to book the slot at exactly the same time, our backend must guarantee that only one of them gets the final position.

This article explains how to design such a system using:

  • Capacity management
  • Availability checking
  • Atomic database operations
  • Race-condition prevention
  • Alternative slot selection
  • Transactions and rollback
  • Concurrent request handling
  • Idempotency
  • Error handling

1. Understanding the Problem

Let's start with the delivery slot model.

A slot contains:

Slot
├── id
├── startTime
├── endTime
├── capacity
└── bookedCount
Enter fullscreen mode Exit fullscreen mode

For example:

Slot ID: SLOT_01
Start: 10:00
End: 12:00
Capacity: 5
Booked Count: 3
Enter fullscreen mode Exit fullscreen mode

The fundamental availability rule is:

bookedCount < capacity
Enter fullscreen mode Exit fullscreen mode

Therefore:

3 < 5 → Available
Enter fullscreen mode Exit fullscreen mode

But:

5 < 5 → False
Enter fullscreen mode Exit fullscreen mode

So the slot is fully booked.


2. The Booking Request

A customer might send:

{
  "customerId": "C001",
  "orderId": "O001",
  "preferredSlotId": "SLOT_01"
}
Enter fullscreen mode Exit fullscreen mode

The backend needs to:

  1. Validate the request.
  2. Find the requested slot.
  3. Check availability.
  4. Reserve capacity.
  5. Create the reservation.
  6. Return a confirmation.

The basic flow is:

Client
   |
   v
Validate Request
   |
   v
Find Slot
   |
   v
Check Availability
   |
   v
Reserve Capacity
   |
   v
Create Reservation
   |
   v
Return Confirmation
Enter fullscreen mode Exit fullscreen mode

3. Why a Simple Availability Check Is Not Enough

A naive implementation might look like this:

const slot = await Slot.findById(slotId);

if (slot.bookedCount >= slot.capacity) {
    throw new Error("Slot is full");
}

slot.bookedCount += 1;

await slot.save();
Enter fullscreen mode Exit fullscreen mode

At first glance, this looks correct.

But there is a serious concurrency problem.


4. The Race Condition Problem

Suppose we have:

Capacity = 5
Booked = 4
Enter fullscreen mode Exit fullscreen mode

There is only one available position.

Now two requests arrive almost simultaneously:

Customer A
Customer B
Enter fullscreen mode Exit fullscreen mode

The operations could happen like this:

Customer A → READ → bookedCount = 4
Customer B → READ → bookedCount = 4

Customer A → available
Customer B → available

Customer A → bookedCount = 5
Customer B → bookedCount = 6
Enter fullscreen mode Exit fullscreen mode

Now we have:

Capacity = 5
Booked = 6
Enter fullscreen mode Exit fullscreen mode

This is overbooking.

The problem isn't the availability condition itself.

The problem is that:

CHECK
Enter fullscreen mode Exit fullscreen mode

and

UPDATE
Enter fullscreen mode Exit fullscreen mode

are separate operations.

Between the check and the update, another request can modify the data.

This is called a:

Race Condition


5. What Is a Race Condition?

A race condition occurs when the result of an operation depends on the timing or ordering of concurrent operations.

In our case:

Request A
   |
   | Check availability
   |
   |--------+
            |
Request B   |
   |        |
   | Check  |
   |        |
   | Update |
   |        |
   |--------+
   |
   | Update
Enter fullscreen mode Exit fullscreen mode

Both requests saw the same state.

That's why simply checking:

if (bookedCount < capacity)
Enter fullscreen mode Exit fullscreen mode

is not enough.

We need to make the critical operation atomic.


6. Atomic Operations

An atomic operation is an operation that happens as one indivisible unit.

For our problem, we want the database to perform:

Check:

bookedCount < capacity

AND

Increment:

bookedCount = bookedCount + 1
Enter fullscreen mode Exit fullscreen mode

as one operation.

Conceptually:

UPDATE delivery_slots
SET booked_count = booked_count + 1
WHERE id = ?
AND booked_count < capacity;
Enter fullscreen mode Exit fullscreen mode

The important part is:

WHERE booked_count < capacity
Enter fullscreen mode Exit fullscreen mode

The database itself decides whether capacity is still available.


7. Why Atomic Updates Solve the Problem

Consider:

Capacity = 5
Booked = 4
Enter fullscreen mode Exit fullscreen mode

Two customers attempt to reserve the last position.

Request A executes:

UPDATE delivery_slots
SET booked_count = booked_count + 1
WHERE id = 'SLOT_01'
AND booked_count < capacity;
Enter fullscreen mode Exit fullscreen mode

The condition is true.

The database updates:

Booked = 5
Enter fullscreen mode Exit fullscreen mode

Now Request B executes the same operation.

The condition becomes:

5 < 5
Enter fullscreen mode Exit fullscreen mode

which is false.

Therefore:

Rows affected = 0
Enter fullscreen mode Exit fullscreen mode

Request B knows that the slot is no longer available.

The final state remains:

Capacity = 5
Booked = 5
Enter fullscreen mode Exit fullscreen mode

No overbooking occurs.


8. A Generic Reservation Algorithm

The core algorithm can be represented as:

FUNCTION reserveSlot(slotId):

    UPDATE slot
    WHERE id = slotId
    AND bookedCount < capacity

    SET bookedCount = bookedCount + 1

    IF no row was updated:
        RETURN "Slot unavailable"

    RETURN "Slot reserved"
Enter fullscreen mode Exit fullscreen mode

The database becomes responsible for enforcing the capacity condition.


9. Implementing It With Node.js

Let's assume we are using Node.js with a SQL database.

A repository method could look like:

async function reserveSlot(slotId) {
    const result = await db.query(
        `
        UPDATE delivery_slots
        SET booked_count = booked_count + 1
        WHERE id = ?
        AND booked_count < capacity
        `,
        [slotId]
    );

    return result.affectedRows === 1;
}
Enter fullscreen mode Exit fullscreen mode

Now:

const reserved = await reserveSlot(slotId);

if (!reserved) {
    return {
        success: false,
        message: "Slot is no longer available"
    };
}
Enter fullscreen mode Exit fullscreen mode

This is much safer than:

SELECT  check  UPDATE
Enter fullscreen mode Exit fullscreen mode

10. The Complete Booking Service

A service layer can coordinate the entire process.

async function bookDeliverySlot({
    customerId,
    orderId,
    preferredSlotId
}) {

    if (!customerId) {
        throw new Error("Customer ID is required");
    }

    if (!orderId) {
        throw new Error("Order ID is required");
    }

    if (!preferredSlotId) {
        throw new Error("Preferred slot ID is required");
    }

    const slot = await findSlotById(preferredSlotId);

    if (!slot) {
        throw new Error("Delivery slot not found");
    }

    const reserved = await reserveSlot(preferredSlotId);

    if (!reserved) {

        const alternatives =
            await findAvailableAlternativeSlots(
                preferredSlotId
            );

        return {
            success: false,
            message: "The selected delivery slot is unavailable",
            alternatives
        };
    }

    const reservation = await createReservation({
        customerId,
        orderId,
        slotId: preferredSlotId
    });

    return {
        success: true,
        message: "Delivery slot booked successfully",
        reservation
    };
}
Enter fullscreen mode Exit fullscreen mode

However, there is another important problem.


11. What Happens If Reservation Creation Fails?

Imagine this sequence:

1. Increment bookedCount
2. Create reservation
Enter fullscreen mode Exit fullscreen mode

The database state becomes:

bookedCount = 5
Enter fullscreen mode Exit fullscreen mode

But then:

createReservation()
Enter fullscreen mode Exit fullscreen mode

fails.

Now the system says:

Booked = 5
Enter fullscreen mode Exit fullscreen mode

even though the customer doesn't actually have a reservation.

We have consumed capacity without creating the booking.

This creates an inconsistent state.


12. Transactions

This is where a database transaction becomes useful.

We want:

Reserve slot
      +
Create reservation
Enter fullscreen mode Exit fullscreen mode

to behave as one logical operation.

Either:

Both succeed
Enter fullscreen mode Exit fullscreen mode

or:

Both fail
Enter fullscreen mode Exit fullscreen mode

Conceptually:

BEGIN TRANSACTION

    Reserve slot

    Create reservation

COMMIT
Enter fullscreen mode Exit fullscreen mode

If something fails:

BEGIN TRANSACTION

    Reserve slot

    Create reservation ❌

ROLLBACK
Enter fullscreen mode Exit fullscreen mode

The rollback restores the previous state.


13. Transaction-Based Implementation

A simplified SQL-style implementation:

async function bookDeliverySlot({
    customerId,
    orderId,
    preferredSlotId
}) {

    const transaction = await db.beginTransaction();

    try {

        const slot = await findSlotById(
            preferredSlotId,
            transaction
        );

        if (!slot) {
            throw new Error("Delivery slot not found");
        }

        const result = await transaction.query(
            `
            UPDATE delivery_slots
            SET booked_count = booked_count + 1
            WHERE id = ?
            AND booked_count < capacity
            `,
            [preferredSlotId]
        );

        if (result.affectedRows === 0) {

            await transaction.rollback();

            const alternatives =
                await findAvailableAlternativeSlots(
                    preferredSlotId
                );

            return {
                success: false,
                message: "The selected delivery slot is unavailable",
                alternatives
            };
        }

        const reservation =
            await createReservation(
                {
                    customerId,
                    orderId,
                    slotId: preferredSlotId
                },
                transaction
            );

        await transaction.commit();

        return {
            success: true,
            message: "Delivery slot booked successfully",
            reservation
        };

    } catch (error) {

        await transaction.rollback();

        throw error;
    }
}
Enter fullscreen mode Exit fullscreen mode

The exact transaction API depends on the database driver or ORM.


14. Finding Alternative Slots

A good booking system shouldn't simply tell the customer:

Slot unavailable.
Enter fullscreen mode Exit fullscreen mode

It can improve the user experience by suggesting alternatives.

For example:

Requested:
12:00 - 14:00

Alternatives:

10:00 - 12:00
14:00 - 16:00
16:00 - 18:00
Enter fullscreen mode Exit fullscreen mode

The query could be conceptually:

SELECT *
FROM delivery_slots
WHERE id != ?
AND booked_count < capacity
AND start_time > CURRENT_TIMESTAMP
ORDER BY start_time;
Enter fullscreen mode Exit fullscreen mode

15. Ranking Alternative Slots

Not every available slot is equally useful.

We could rank alternatives according to:

Option 1 — Closest time

Requested: 12:00

10:00
14:00
16:00
18:00
Enter fullscreen mode Exit fullscreen mode

Option 2 — Earliest available

10:00
14:00
16:00
18:00
Enter fullscreen mode Exit fullscreen mode

Option 3 — Business priority

For example:

Same day
↓
Nearest time
↓
Lowest delivery cost
Enter fullscreen mode Exit fullscreen mode

The business rules determine the sorting strategy.


16. Alternative Slot Function

A simple implementation:

async function findAvailableAlternativeSlots(
    preferredSlotId
) {

    const preferredSlot =
        await findSlotById(preferredSlotId);

    if (!preferredSlot) {
        return [];
    }

    return await Slot.find({
        _id: {
            $ne: preferredSlotId
        },
        bookedCount: {
            $lt: "$capacity"
        },
        startTime: {
            $gt: new Date()
        }
    }).sort({
        startTime: 1
    });
}
Enter fullscreen mode Exit fullscreen mode

The exact syntax depends on the database.

For SQL databases, the equivalent condition would typically be:

booked_count < capacity
Enter fullscreen mode Exit fullscreen mode

17. MongoDB Version

If the backend uses MongoDB, the same principle can be implemented with a conditional atomic update.

For example:

const slot = await DeliverySlot.findOneAndUpdate(
    {
        _id: slotId,
        $expr: {
            $lt: ["$bookedCount", "$capacity"]
        }
    },
    {
        $inc: {
            bookedCount: 1
        }
    },
    {
        new: true
    }
);
Enter fullscreen mode Exit fullscreen mode

The important part is:

$expr: {
    $lt: ["$bookedCount", "$capacity"]
}
Enter fullscreen mode Exit fullscreen mode

combined with:

$inc: {
    bookedCount: 1
}
Enter fullscreen mode Exit fullscreen mode

The operation is performed atomically for the document.

If the result is:

null
Enter fullscreen mode Exit fullscreen mode

the slot could not be reserved.


18. Handling Concurrent Requests With MongoDB

Suppose:

Capacity = 5
Booked = 4
Enter fullscreen mode Exit fullscreen mode

Two requests execute:

findOneAndUpdate(...)
Enter fullscreen mode Exit fullscreen mode

Request A succeeds:

Booked = 5
Enter fullscreen mode Exit fullscreen mode

Request B evaluates:

5 < 5
Enter fullscreen mode Exit fullscreen mode

which is false.

Therefore:

slot === null
Enter fullscreen mode Exit fullscreen mode

Request B can then search for alternatives.

This protects the shared resource from overbooking.


19. The Complete Flow

The complete system can be represented as:

                    Customer
                       |
                       v
                Booking Request
                       |
                       v
                Validate Input
                       |
             +---------+---------+
             |                   |
          Invalid              Valid
             |                   |
             v                   v
        Return Error       Find Requested Slot
                                 |
                         +-------+-------+
                         |               |
                      Not Found        Found
                         |               |
                         v               v
                   Return Error    Attempt Atomic
                                    Reservation
                                         |
                              +----------+----------+
                              |                     |
                           Success                Failed
                              |                     |
                              v                     v
                       Create Booking       Find Alternatives
                              |                     |
                              v              +------+------+
                           Commit            |             |
                              |           Found          None
                              v             |             |
                          Success           v             v
                                     Return Options   Return Error
Enter fullscreen mode Exit fullscreen mode

20. API Design

A REST API might expose:

POST /api/delivery-slots/book
Enter fullscreen mode Exit fullscreen mode

Request:

{
  "customerId": "C001",
  "orderId": "O001",
  "preferredSlotId": "SLOT_01"
}
Enter fullscreen mode Exit fullscreen mode

Successful response:

{
  "success": true,
  "message": "Delivery slot booked successfully",
  "reservation": {
    "id": "RES_001",
    "slotId": "SLOT_01",
    "customerId": "C001",
    "orderId": "O001"
  }
}
Enter fullscreen mode Exit fullscreen mode

If the slot becomes unavailable:

{
  "success": false,
  "message": "The selected delivery slot is unavailable",
  "alternatives": [
    {
      "id": "SLOT_02",
      "startTime": "14:00",
      "endTime": "16:00"
    },
    {
      "id": "SLOT_03",
      "startTime": "16:00",
      "endTime": "18:00"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

21. HTTP Status Codes

The API can also use appropriate HTTP status codes.

For successful booking:

201 Created
Enter fullscreen mode Exit fullscreen mode

Invalid request:

400 Bad Request
Enter fullscreen mode Exit fullscreen mode

Unknown slot:

404 Not Found
Enter fullscreen mode Exit fullscreen mode

Slot unavailable:

409 Conflict
Enter fullscreen mode Exit fullscreen mode

Server/database failure:

500 Internal Server Error
Enter fullscreen mode Exit fullscreen mode

Using:

409 Conflict
Enter fullscreen mode Exit fullscreen mode

for an unavailable shared resource is particularly useful because the request itself can be valid while the resource state has changed.


22. Idempotency

There is another important issue.

Imagine the customer clicks:

Book
Enter fullscreen mode Exit fullscreen mode

and the request succeeds.

But the network is slow.

The frontend doesn't receive the response.

The customer clicks again.

Now the backend receives:

Request 1
Request 2
Enter fullscreen mode Exit fullscreen mode

Both may attempt to reserve capacity.

This can create duplicate reservations.

A common solution is an idempotency key.

For example:

Idempotency-Key: 8d7f9c21
Enter fullscreen mode Exit fullscreen mode

The backend stores the result associated with that key.

If the same request arrives again:

Same Idempotency Key
        |
        v
Existing result?
        |
       Yes
        |
        v
Return previous result
Enter fullscreen mode Exit fullscreen mode

Instead of creating another reservation.


23. Database Constraints

Application logic should not be the only protection.

The database should also enforce important invariants where possible.

For example, we want:

bookedCount <= capacity
Enter fullscreen mode Exit fullscreen mode

The exact constraint strategy depends on the database.

This leads to an important backend principle:

Business-critical invariants should be protected as close to the data as practical.

The application controls the workflow, while the database protects data integrity.


24. Why "Read Then Write" Is Dangerous

This pattern is common:

const slot = await getSlot();

if (slot.bookedCount < slot.capacity) {

    slot.bookedCount++;

    await updateSlot(slot);
}
Enter fullscreen mode Exit fullscreen mode

It looks reasonable, but under concurrency it becomes:

READ
  ↓
CHECK
  ↓
WAIT
  ↓
WRITE
Enter fullscreen mode Exit fullscreen mode

Another request can modify the resource during that window.

A safer pattern is:

CONDITIONAL UPDATE
Enter fullscreen mode Exit fullscreen mode

For example:

UPDATE delivery_slots
SET booked_count = booked_count + 1
WHERE id = ?
AND booked_count < capacity;
Enter fullscreen mode Exit fullscreen mode

This moves the critical decision into the database operation itself.


25. Edge Cases

A production-ready implementation should consider more than the happy path.

Missing customer

Customer ID is required
Enter fullscreen mode Exit fullscreen mode

Missing order

Order ID is required
Enter fullscreen mode Exit fullscreen mode

Missing slot

Preferred slot ID is required
Enter fullscreen mode Exit fullscreen mode

Unknown slot

Delivery slot not found
Enter fullscreen mode Exit fullscreen mode

Full slot

Find alternatives
Enter fullscreen mode Exit fullscreen mode

No alternatives

No available delivery slots
Enter fullscreen mode Exit fullscreen mode

Concurrent booking

Use atomic reservation
Enter fullscreen mode Exit fullscreen mode

Reservation creation failure

Rollback transaction
Enter fullscreen mode Exit fullscreen mode

Duplicate booking

Use idempotency / unique constraints
Enter fullscreen mode Exit fullscreen mode

Slot in the past

The system should reject expired slots:

startTime <= currentTime
Enter fullscreen mode Exit fullscreen mode

Cancelled reservation

If a customer cancels:

bookedCount = bookedCount - 1
Enter fullscreen mode Exit fullscreen mode

This operation should also be performed safely.


26. Cancellation

Booking isn't the only operation that affects capacity.

Suppose:

Capacity = 5
Booked = 5
Enter fullscreen mode Exit fullscreen mode

A customer cancels.

We need:

Booked = 4
Enter fullscreen mode Exit fullscreen mode

A safe operation could be:

UPDATE delivery_slots
SET booked_count = booked_count - 1
WHERE id = ?
AND booked_count > 0;
Enter fullscreen mode Exit fullscreen mode

Again, the condition protects the invariant:

bookedCount >= 0
Enter fullscreen mode Exit fullscreen mode

27. Testing Concurrent Booking

Concurrency should not only be discussed theoretically.

It should also be tested.

Suppose:

Capacity = 100
Booked = 99
Enter fullscreen mode Exit fullscreen mode

Send:

10 concurrent requests
Enter fullscreen mode Exit fullscreen mode

Expected result:

1 successful reservation
9 rejected requests
Enter fullscreen mode Exit fullscreen mode

The final state must be:

Capacity = 100
Booked = 100
Enter fullscreen mode Exit fullscreen mode

Never:

Booked = 101
Enter fullscreen mode Exit fullscreen mode

A conceptual test:

const requests = Array.from(
    { length: 10 },
    (_, index) =>
        bookDeliverySlot({
            customerId: `C${index}`,
            orderId: `O${index}`,
            preferredSlotId: "SLOT_01"
        })
);

const results = await Promise.allSettled(requests);

const successfulBookings =
    results.filter(
        result =>
            result.status === "fulfilled" &&
            result.value.success
    );

console.log(
    successfulBookings.length
);
Enter fullscreen mode Exit fullscreen mode

For a slot with one remaining position, the expected successful booking count is:

1
Enter fullscreen mode Exit fullscreen mode

28. Important Architecture Principle

This problem demonstrates an important backend concept:

A delivery slot is not just a database record. It is a shared, limited resource.

Whenever multiple requests can consume the same limited resource, we need to think about:

Concurrency
+
Consistency
+
Atomicity
+
Data Integrity
Enter fullscreen mode Exit fullscreen mode

The same concepts appear in:

  • Inventory systems
  • Seat booking
  • Hotel rooms
  • Appointment scheduling
  • Warehouse capacity
  • Payment processing
  • Ticket booking
  • Restaurant reservations
  • Rate-limit counters

The resource changes, but the concurrency problem remains similar.


29. A Better Production Architecture

A production system might separate responsibilities into layers:

Controller
    |
    v
Booking Service
    |
    v
Slot Repository
    |
    v
Database
Enter fullscreen mode Exit fullscreen mode

Controller

Responsible for:

HTTP request
HTTP response
Input extraction
Enter fullscreen mode Exit fullscreen mode

Service

Responsible for:

Business rules
Booking workflow
Alternative selection
Transactions
Enter fullscreen mode Exit fullscreen mode

Repository

Responsible for:

Database queries
Atomic updates
Persistence
Enter fullscreen mode Exit fullscreen mode

This separation makes the system easier to test and maintain.


30. Example Service Architecture

class DeliverySlotService {

    async book({
        customerId,
        orderId,
        preferredSlotId
    }) {

        this.validateRequest({
            customerId,
            orderId,
            preferredSlotId
        });

        const slot =
            await this.slotRepository.findById(
                preferredSlotId
            );

        if (!slot) {
            throw new Error(
                "Delivery slot not found"
            );
        }

        const reservation =
            await this.slotRepository.reserve(
                preferredSlotId,
                customerId,
                orderId
            );

        if (!reservation) {

            const alternatives =
                await this.slotRepository
                    .findAlternatives(
                        preferredSlotId
                    );

            return {
                success: false,
                alternatives
            };
        }

        return {
            success: true,
            reservation
        };
    }
}
Enter fullscreen mode Exit fullscreen mode

The service doesn't need to know the details of SQL or MongoDB.

That's the responsibility of the repository.


31. Key Lessons

The most important lessons from delivery-slot allocation are:

1. Checking availability isn't enough

This:

if (bookedCount < capacity)
Enter fullscreen mode Exit fullscreen mode

doesn't guarantee safe booking under concurrency.


2. Protect the critical section

Use an atomic operation:

UPDATE ...
WHERE booked_count < capacity
Enter fullscreen mode Exit fullscreen mode

3. Use transactions when multiple changes must succeed together

For example:

Reserve capacity
+
Create reservation
Enter fullscreen mode Exit fullscreen mode

4. Handle concurrency explicitly

Assume that multiple users can request the same resource simultaneously.

Don't design the system as if requests are processed one at a time.


5. Provide alternatives

A failed booking doesn't have to mean a bad user experience.

Return useful alternatives.


6. Protect against duplicate requests

Idempotency is important for booking and payment-like operations.


7. Test the race condition

Concurrency bugs often don't appear during normal testing.

Stress the critical operation with simultaneous requests.


32. Final Implementation Strategy

The complete strategy can be summarized as:

Receive Request
       ↓
Validate Input
       ↓
Find Slot
       ↓
Is Slot Valid?
   ↓           ↓
 No           Yes
 ↓             ↓
Error     Atomic Reservation
               ↓
       Reservation Successful?
          ↓             ↓
         No            Yes
         ↓              ↓
 Find Alternatives   Create Reservation
         ↓              ↓
    Return Result    Commit Transaction
                         ↓
                    Booking Success
Enter fullscreen mode Exit fullscreen mode

The core invariant is:

bookedCount <= capacity
Enter fullscreen mode Exit fullscreen mode

And the critical rule is:

Do not separate the availability check
from the capacity update when concurrency matters.
Enter fullscreen mode Exit fullscreen mode

Instead of:

READ
 ↓
CHECK
 ↓
UPDATE
Enter fullscreen mode Exit fullscreen mode

prefer:

CONDITIONAL ATOMIC UPDATE
Enter fullscreen mode Exit fullscreen mode

For example:

UPDATE delivery_slots
SET booked_count = booked_count + 1
WHERE id = ?
AND booked_count < capacity;
Enter fullscreen mode Exit fullscreen mode

Then combine the reservation creation with a transaction when both operations must remain consistent.


Conclusion

Delivery slot allocation may initially look like a simple CRUD operation:

Find slot
→ Check capacity
→ Increment booked count
Enter fullscreen mode Exit fullscreen mode

But once multiple customers can access the same slot concurrently, the problem becomes a concurrency and data-consistency problem.

A robust implementation therefore needs:

Validation
+
Atomic operations
+
Transactions
+
Concurrency control
+
Alternative slots
+
Idempotency
+
Database integrity
Enter fullscreen mode Exit fullscreen mode

The most important principle is simple:

When multiple requests compete for a limited shared resource, the operation that consumes that resource must be concurrency-safe.

This principle goes far beyond delivery slots. It is one of the fundamental ideas behind reliable backend systems.

Top comments (0)