Hone logo
Hone
Problems

Implement Background Data Synchronization in Angular

This challenge focuses on implementing a robust background data synchronization mechanism in an Angular application. This is crucial for applications that need to maintain data consistency between the client and a server, even when the user is offline or experiences intermittent network connectivity. The goal is to allow users to make changes offline and have those changes seamlessly synced to the server when connectivity is restored.

Problem Description

You are tasked with building a feature that synchronizes data between an Angular client and a backend API. The application should allow users to perform data operations (e.g., create, update, delete) locally. These operations should be queued and then synchronized with the backend in the background when the application is online.

Key Requirements:

  • Offline Operations: Users should be able to perform data modifications (create, update, delete) when the device is offline.
  • Operation Queueing: All offline operations must be stored locally in a persistent queue.
  • Background Synchronization: When the application detects an online status, it should attempt to synchronize the queued operations with the backend API.
  • Conflict Resolution (Basic): Implement a basic strategy to handle potential conflicts during synchronization. For this challenge, assume a simple "last write wins" approach for updates, where the most recent change to a specific record on the server takes precedence if a conflict arises.
  • Status Indicators: Provide visual feedback to the user about the synchronization status (e.g., syncing, synced, offline).
  • Error Handling: Gracefully handle synchronization errors and potentially retry failed operations.

Expected Behavior:

  1. User performs an operation (e.g., adds a new item) while offline. The operation is added to a local queue.
  2. Application detects online status.
  3. The queued operation is sent to the backend API.
  4. If successful, the operation is removed from the queue and the UI is updated.
  5. If an error occurs (e.g., server error, conflict), the operation might be retried or marked as failed, with appropriate user notification.

Edge Cases to Consider:

  • Network Intermittency: Rapid switching between online and offline states.
  • Multiple Offline Operations: A large number of operations queued while offline.
  • Concurrent Offline Changes: If the same data item is modified multiple times offline before sync.
  • Server-Side Conflicts: What happens if the same record was updated on the server independently while the client was offline.

Examples

Example 1: Creating a new item offline

Input:
- User is offline.
- User creates a new "Task" with title "Buy groceries".
- The application is then brought online.

Output:
- The "Task" "Buy groceries" is successfully created on the backend.
- The local queue of operations is cleared for this item.
- The UI reflects the newly created task.
- A status indicator shows "Synced".

Example 2: Updating an item offline and resolving a conflict

Scenario:
- User is online and creates "Task A" with status "Pending".
- User goes offline.
- User updates "Task A" to status "In Progress".
- Meanwhile, on the server (via another channel), "Task A" status is updated to "Completed".
- User comes back online.

Process:
1. The client sends the update for "Task A" (status: "In Progress").
2. The backend detects a conflict: the server version has a newer modification date/timestamp.
3. Backend applies the "last write wins" strategy: the server's "Completed" status overwrites the client's "In Progress" status.
4. Backend returns a conflict resolution response to the client.
5. The client updates its local state to match the server's state ("Task A" status: "Completed") and clears the operation from the queue.

Output:
- "Task A" on the client now shows status "Completed".
- The local queue is updated.
- The status indicator shows "Synced".

Example 3: Deleting an item offline that was also updated on the server

Scenario:
- User is online and creates "Task B".
- User goes offline.
- User deletes "Task B".
- Meanwhile, on the server, "Task B" is updated (e.g., its title is changed).
- User comes back online.

Process:
1. The client sends the delete operation for "Task B".
2. The backend detects that "Task B" has been modified since the client last synced.
3. The backend prioritizes the delete operation if it's considered more critical or if the server's last modification is also being addressed by the sync. For this challenge, assume the delete operation, if received by the server, will proceed, and the server will remove "Task B". The client will then reflect this deletion.

Output:
- "Task B" is no longer present on the client or the server.
- The local queue is updated.
- The status indicator shows "Synced".

Constraints

  • Frontend Framework: Angular (latest stable version).
  • Language: TypeScript.
  • Offline Storage: Use browser's localStorage or IndexedDB for persistent offline storage of operations.
  • Backend API: Assume a RESTful API with endpoints like:
    • POST /tasks: Create a new task.
    • PUT /tasks/:id: Update an existing task.
    • DELETE /tasks/:id: Delete a task.
    • Responses will include success status, updated data, and potentially conflict indicators or error messages.
  • Network Status Detection: Utilize browser's navigator.onLine property and/or online/offline events.
  • Performance: The synchronization process should not block the main thread and should be efficient for a moderate number of queued operations (e.g., up to a few hundred).
  • No External Libraries (for core sync logic): Implement the core synchronization logic using built-in browser APIs and Angular features. You can use libraries for UI components if desired.

Notes

  • Consider the structure of your operation queue. Each item in the queue should ideally contain the type of operation (CREATE, UPDATE, DELETE), the data payload, and potentially a timestamp or version identifier for conflict resolution.
  • Think about how to represent different types of data objects and their unique identifiers.
  • The status indicator can be a simple text message, an icon, or a more sophisticated component.
  • For basic conflict resolution, you'll need a way to identify if a record on the server has been modified since the client last saw it. Timestamps or version numbers are common approaches.
  • Consider the order of operations. Deletes should generally be processed before updates or creations for the same item.
  • A service in Angular is a good place to encapsulate the synchronization logic.
Loading editor...
typescript