5

Handling Optimistic Concurrency in Web Frontends

 2 years ago
source link: https://blog.bitsrc.io/handling-optimistic-concurrency-in-web-frontends-1ae7eb0e57a4
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Handling Optimistic Concurrency in Web Frontends

Implementing Optimistic Concurrency in Frontend

1*rrfbQ-3vQMByL48dtQxDhA.png

Building scalable web applications requires developers to implement resilient measures to handle concurrent data access. If developers do not handle concurrent data management, there is a greater possibility of overriding one user’s data with another, thus leading to data loss.

Therefore, many developers have implemented some concurrency control to handle specific cases like this. A common approach involves the use of optimistic concurrency.

What is Optimistic Concurrency?

Optimistic concurrency is a strategy that ensures that the item that a user updates or deletes is the exact item present in the database. It helps prevent your write/delete requests from being overridden by other user requests.

How Does Optimistic Concurrency Work?

Consider the figure shown below to understand optimistic concurrency better.

0*rHBisDoWeHBAXxsk.png

Figure 1 — Illustrating Optimistic Concurrency

Optimistic concurrency requires an item to have an attribute that acts as a version number. For example, a data item can have a unique timestamp or a sequentially increased number serving as the version number (as shown in figure 1).

When the client requests an item, the backend will send the version number along with the item. The frontend must keep the version number and send it for every update/delete request made to the item. The backend will then obtain the version number sent by the frontend and permit the update/delete request only if the version number sent by the client matches the version number stored in the database for the item.

If the version numbers don’t match, another user has already updated the item. So allowing the update would cause the data to be overridden by old data. Optimistic concurrency will help prevent you from accidentally overriding changes made by others or prevent others from overriding your changes.

When Should I Use Optimistic Concurrency?

After gaining a brief understanding of optimistic concurrency, it’s essential to identify specific scenarios in that developers can utilize optimistic concurrency.

1. Prioritize performance

Optimistic concurrency is recommended if your application requires more performance at database writes than pessimistic concurrency. It is because, with optimistic concurrency control, the database does not have to acquire and release locks when reading. However, optimistic concurrency has to maintain a lock while making updates to check the version number of the data.

2. Data has more reads and fewer concurrent writes

Optimistic concurrency is cost-effective if the data has more reads with fewer concurrent writes.

3. Business transactions are not correlated to database transactions

If your business transactions are not related to a database transaction, you will be better off implementing optimistic concurrency controls rather than a pessimistic approach. For example, in three-tier web applications, most business transactions have no relationship with the database transaction. Therefore, it is challenging to maintain locks across database transactions. In these cases, optimistic concurrency is most recommended.

How to Implement Optimistic Concurrency in the Frontend

All use cases for optimistic concurrency revolve around a database. Therefore, this raises the question, “How does it apply to frontends?”.

The frontend is a vital part of implementing optimistic concurrency. For example, consider a scenario where a client (Angular application) requests information regarding a post.

Initially, the Angular application makes a GET request to the backend. Afterward, the backend will return information regarding the post along with an attribute timestamp (acting as the version number) that identifies the last updated time of the post. The format of the output is shown below.

{
"id": 1,
"title": "My Post",
"description": "This is a sample post",
"timestamp": 1656135975511
}

The Angular application must store the timestamp in the frontend and send the timestamp for every update or delete request. The backend would then verify the timestamp to ensure that the item the client uses is the most recent one (DynamoDB does this using ConditionExpressions).

Upon successful update, the backend would generate a new version (since the data has changed) and return it to the Angular application. The Angular application must store the new timestamp generated by the backend and update its state to ensure it is using the latest version. Then, it will reject all requests made using the previous version number. You can see this in the snippet below.

const updatePost = () => {
const patchObject: Post = {
name: "Updating name",
};

const reqObject = {
post: patchObject,
currentVersion: this.loadedPost.timestamp,
};

this.postService.updatePost(reqObject).subscribe(
(data) => {
this.post.name = data.name;
this.post.timestamp = data.newVersionNumber; // store new version number and update the state of the loaded post
},
(error) => {
console.error(err);
}
);
};

How to Handle Errors with Optimistic Concurrency

After you’ve implemented optimistic concurrency for your frontend application, you must make sure that you handle errors related to it gracefully.

Here are some practices highly recommended to any developer looking to handle optimistic concurrency gracefully.

1. Return identifiable error codes

Ensure that you return an understandable response code from the backend. For example, the HTTP response code — 409 is suitable for these cases to indicate a conflict.

2. Provide information that the user can understand

Since these are not common 500 errors, you cannot provide messages like “We ran into an error, please try again.” The error message provided in these cases must be specific. A good error message for an optimistic concurrent error is “This post was edited elsewhere.”

3. Help the user solve the error on their own

It’s essential to help the user solve this error on their own. You can implement this by enabling the user to reload the content with the latest version. For example, you can provide a button to reload the content on the page causing the error.

Current Implementations of Optimistic Concurrency in Frontends

Though optimistic concurrency in frontends seems like a new area, it has been around for some time.

Developers might recognize optimistic concurrency management in the frontend when opening pull requests on GitHub. However, since it’s impossible to acquire locks on single files due to the distributed nature of Git, the only approach is to let the last person making the changes determine the correct “version” of the file.

On the other hand, frontend content management platforms such as Medium and WriterGate utilize optimistic concurrency to prevent the content from being edited across different tabs.

For example, if one user makes a change on one tab, the content in the second tab will not get saved as the version present in the database has changed. Therefore, these systems automatically prevent the content from being saved to avoid potential data loss. Additionally, they’ve implemented graceful error handling allowing users to reload the content with the latest content.

0*QTFPKOAC0ZWTm75k.png

Figure 2 — Optimistic concurrency management in WriterGate

0*T2QvJ22U3vJei5Tu.png

Figure 3 — Optimistic concurrency management on Medium

These platforms allow the user to resolve the error by reloading the content, thus ensuring that no accidental data loss occurs to content saved by other users for the same item.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK