Software Architecture Patterns for Serverless Systems by John Gilbert
Author:John Gilbert
Language: eng
Format: epub, mobi
Publisher: Packt Publishing Pvt. Ltd.
Published: 2021-06-29T00:00:00+00:00
Inverse optimistic locking
We use the traditional optimistic locking technique to prevent multiple users from updating the same record concurrently. We only allow a user to update a record if the oplock value has not changed since the user retrieved the data. If another user has updated the record and thus the oplock value, then we throw an exception when the current user attempts to update the record and force the user to retrieve the data again before proceeding with the update. This ensures that we perform updates sequentially, and it requires human interaction to resolve any potential conflicts. We can use this traditional technique in BFF services command functions when users modify data.
Conversely, we use the inverse optimistic locking technique in downstream asynchronous stream processors to provide both idempotence and order tolerance. It ensures that older or duplicate events do not overwrite the most recent data. Instead of forcing a transaction to retry when an oplock fails, they simply do the opposite; they drop the older or duplicate event.
The following DynamoDB example shows the typical structure of a mapping step for a stream processing pipeline that creates a materialized view. We are using uow.event.timestamp as the new oplock value. ConditionExpression compares the old oplock value against the new value. If the new value is greater than the old value, then we allow the update to proceed. The attribute_not_exists clause handles the case where the record is new and there is no old oplock to compare against:
export const toUpdateRequest = (uow) => ({
Key: {
pk: uow.event.thing.id,
sk: 'thing',
},
ExpressionAttributeNames: {
'#name': 'name',
'#oplock': 'timestamp',
},
ExpressionAttributeValues: {
':name': 'Thing One',
':timestamp': uow.event.timestamp,
},
UpdateExpression: 'SET #name = :name,
#oplock = :timestamp',
ConditionExpression: 'attribute_not_exists(#oplock)
OR :timestamp > #oplock',
});
The first thing to notice in this example that is different with an inverse oplock is that the comparison is greater than instead of equals. If the value is equal to the previous value, then this indicates that we have already processed this event. If the value is less than the previous value, then this indicates that we are processing an older event out of order. When this value is greater than the previous value, we know we have a newer event, so we can proceed with the update.
The last piece of the puzzle is handling the response value returned from the call to update the database. The AWS SDK will throw an exception when error.code is returned. We don't want to ignore all errors, so we catch the exception and check for the ConditionalCheckFailedException code. We re-throw all other exceptions for fault handling, as we covered in Chapter 4, Trusting Facts and Eventual Consistency. When we do ignore an exception, it is good practice to log a metric so that we can track how frequently this happens and assess whether or not there is a root cause that we should address:
db.update(params).promise()
.catch((err) => {
if (err.code !== 'ConditionalCheckFailedException') {
throw err;
}
});
When using the inverse optimistic locking technique, it is important to ensure that we are not dropping important data when we ignore older events.
Download
Software Architecture Patterns for Serverless Systems by John Gilbert.mobi
This site does not store any files on its server. We only index and link to content provided by other sites. Please contact the content providers to delete copyright contents if any and email us, we'll remove relevant links or contents immediately.
API Testing and Development with Postman by Dave Westerveld(3468)
Learning C# by Developing Games with Unity 2020 by Harrison Ferrone(2466)
Software Architecture for Busy Developers by Stéphane Eyskens(2170)
2021 Beginners Guide to Python Programming Language: A Crash Course to Mastering Python in One Hour by Elmer Gary & Elmer Gary(1880)
Machine Learning for Algorithmic Trading by Stefan Jansen(1623)
Hands-On ROS for Robotics Programming by Bernardo Ronquillo Japón(1563)
Delphi GUI Programming with FireMonkey by Andrea Magni(1449)
Game Development Projects with Unreal Engine by Hammad Fozi & Goncalo Marques & David Pereira & Devin Sherry(1392)
Cloud Native with Kubernetes by Alexander Raul(1370)
Datadog Cloud Monitoring Quick Start Guide by Thomas Kurian Theakanath(1339)
Software Architecture Patterns for Serverless Systems by John Gilbert(1334)
Practical Node-RED Programming by Taiji Hagino(1323)
Automate It with Zapier by Kelly Goss(1315)
Practical System Programming for Rust Developers by Prabhu Eshwarla(1306)
Mastering React Test-Driven Development by Daniel Irvine(1286)
Delphi Programming Projects by William Duarte(1284)
Developing Multi-Platform Apps with Visual Studio Code by Ovais Mehboob Ahmed Khan & Khusro Habib & Chris Dias(1246)
Ghidra Software Reverse Engineering for Beginners by A. P. David(1240)
Learn Spring for Android Application Development by S. M. Mohi Us Sunnat(1232)
