Skip to content

Adds transaction with watched key example script. #2297

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
This folder contains example scripts showing how to use Node Redis in different scenarios.

| File Name | Description |
|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `blocking-list-pop.js` | Block until an element is pushed to a list |
| `bloom-filter.js` | Space efficient set membership checks with a [Bloom Filter](https://en.wikipedia.org/wiki/Bloom_filter) using [RedisBloom](https://redisbloom.io) |
| `command-with-modifiers.js` | Define a script that allows to run a command with several modifiers |
| `connect-as-acl-user.js` | Connect to Redis 6 using an ACL user |
| `count-min-sketch.js` | Estimate the frequency of a given event using the [RedisBloom](https://redisbloom.io) Count-Min Sketch |
| `cuckoo-filter.js` | Space efficient set membership checks with a [Cuckoo Filter](https://en.wikipedia.org/wiki/Cuckoo_filter) using [RedisBloom](https://redisbloom.io) |
| `get-server-time.js` | Get the time from the Redis server |
| `hyperloglog.js` | Showing use of Hyperloglog commands [PFADD, PFCOUNT and PFMERGE](https://redis.io/commands/?group=hyperloglog) |
| `hyperloglog.js` | Showing use of Hyperloglog commands [PFADD, PFCOUNT and PFMERGE](https://redis.io/commands/?group=hyperloglog) |
| `lua-multi-incr.js` | Define a custom lua script that allows you to perform INCRBY on multiple keys |
| `managing-json.js` | Store, retrieve and manipulate JSON data atomically with [RedisJSON](https://redisjson.io/) |
| `pubsub-publisher.js` | Adds multiple messages on 2 different channels messages to Redis |
Expand All @@ -25,10 +25,11 @@ This folder contains example scripts showing how to use Node Redis in different
| `time-series.js` | Create, populate and query timeseries data with [Redis Timeseries](https://redistimeseries.io) |
| `topk.js` | Use the [RedisBloom](https://redisbloom.io) TopK to track the most frequently seen items. |
| `stream-consumer-group.js` | Reads entties from a [Redis Stream](https://redis.io/topics/streams-intro) as part of a consumer group using the blocking `XREADGROUP` command |
| `transaction-with-watch.js` | An Example of [Redis transaction](https://redis.io/docs/manual/transactions) with `WATCH` command on isolated connection with optimistic locking |

## Contributing

We'd love to see more examples here. If you have an idea that you'd like to see included here, submit a Pull Request and we'll be sure to review it! Don't forget to check out our [contributing guide](../CONTRIBUTING.md).
We'd love to see more examples here. If you have an idea that you'd like to see included here, submit a Pull Request and we'll be sure to review it! Don't forget to check out our [contributing guide](../CONTRIBUTING.md).

## Setup

Expand All @@ -46,21 +47,21 @@ $ npm install

When adding a new example, please follow these guidelines:

* Add your code in a single JavaScript or TypeScript file per example, directly in the `examples` folder
* Do not introduce other dependencies in your example
* Give your `.js` file a meaningful name using `-` separators e.g. `adding-to-a-stream.js` / `adding-to-a-stream.ts`
* Indent your code using 2 spaces
* Use the single line `//` comment style and comment your code
* Add a comment at the top of your `.js` / `.ts` file describing what your example does
* Add a comment at the top of your `.js` / `.ts` file describing any Redis commands that need to be run to set up data for your example (try and keep this minimal)
* Use semicolons
* Use `async` and `await`
* Use single quotes, `'hello'` not `"hello"`
* Use [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) when embedding expressions in strings
* Unless your example requires a connection string, assume Redis is on the default localhost port 6379 with no password
* Use meaningful example data, let's not use `foo`, `bar`, `baz` etc!
* Leave an empty line at the end of your `.js` file
* Update this `README.md` file to add your example to the table
- Add your code in a single JavaScript or TypeScript file per example, directly in the `examples` folder
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason to change anything in this README.md at all except for adding a new line entry in the table for your new script?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sailingwithsandeep please see @simonprickett's question above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@simonprickett Hey so sorry i just realised i changed the order of readme file's coding guidelines list. it happened because i copied that readme file from previous pull request and somehow changed the order. i hope you understand my concern. Again extremely sorry for changing unwanted things. (P.S. I am so excited that i am contributing into redis community so, given that state i might have rushed it.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't rush @sailingwithsandeep and only change the things that are necessary :) please change it back and we will re-review.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@simonprickett @SuzeShardlow Hey i committed the changes hopefully this time there won't be an issue. Again sorry for the trouble.

- Do not introduce other dependencies in your example
- Give your `.js` file a meaningful name using `-` separators e.g. `adding-to-a-stream.js` / `adding-to-a-stream.ts`
- Indent your code using 2 spaces
- Use the single line `//` comment style and comment your code
- Add a comment at the top of your `.js` / `.ts` file describing what your example does
- Add a comment at the top of your `.js` / `.ts` file describing any Redis commands that need to be run to set up data for your example (try and keep this minimal)
- Use semicolons
- Use `async` and `await`
- Use single quotes, `'hello'` not `"hello"`
- Use [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) when embedding expressions in strings
- Unless your example requires a connection string, assume Redis is on the default localhost port 6379 with no password
- Use meaningful example data, let's not use `foo`, `bar`, `baz` etc!
- Leave an empty line at the end of your `.js` file
- Update this `README.md` file to add your example to the table

Use [connect-as-acl-user.js](./connect-as-acl-user.js) as a guide to develop a well formatted example script.

Expand All @@ -86,5 +87,4 @@ await client.connect();
// Add your example code here...

await client.quit();

```
50 changes: 50 additions & 0 deletions examples/transaction-with-watch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// This example shows you sample transaction for how to achieve optimistic locking using WATCH with check-and-set (CAS) behavior.
// If any watched key changes outside the session then entire transaction will be aborted.
// To know more about isolated execution & redis transaction: https://github.com/redis/node-redis/blob/master/docs/isolated-execution.md
// https://redis.io/docs/manual/transactions

// We just have to repeat the operation by calling the function again(recursion) hoping this time we'll not get race condition.
// restrictFunctionCalls is a counter function to limit recursive calls

import { createClient, WatchError } from 'redis';

const client = createClient();
await client.connect();

/**
*
* @param {function} fn
* @param {number} maxCalls
* @returns a function that is being called based on maxCalls
*/
function restrictFunctionCalls(fn, maxCalls) {
let count = 1;
return function (...args) {
return count++ < maxCalls ? fn(...args) : false;
};
}
let fn = restrictFunctionCalls(transaction, 4);
async function transaction() {
try {
await client.executeIsolated(async (isolatedClient) => {
await isolatedClient.watch('paymentId:1259');
const multi = isolatedClient
.multi()
.set('paymentId:1259', 'Payment Successfully Completed!')
.set('paymentId:1260', 'Refund Processed Successfully!');
await multi.exec();
console.log('Transaction completed Successfully!');
});
} catch (error) {
if (error instanceof WatchError) {
console.log('Transaction Failed Due To Concurrent Modification!');
fn();
} else {
console.log(`Error: ${error}`);
}
}
}

transaction();

await client.quit();