Memcached
Key takeaways
MemcachedCache | Distributed cache that stores values in a Memcached store. |
MemcachedLock | Distributed lock that is implemented based on a Memcached store. |
Introduction
In this tutorial, you will understand how to create and manage a cache and a distributed lock, both based on a Memcached store.
First, we will look at the pre-requisites. Then, we will see how to create and perform relevant operations through examples. We will finalize the tutorial with a practical example of how to use distributed locks.
Pre-requisites
In order to use these components, we need to install the Memcached module first. The following command shows how to do this:
npm install pip-services4-prometheus-node --save
go get -u github.com/pip-services4/pip-services4-go/pip-services4-memcached-go@latest
pip install pip-services4-memcached
MemcachedCache
This component provides a way to create a distributed cache based on the Memcached database. In this section, we will learn how to install and perform CRUD operations with it.
Pre-requisites
To use this component, we need to import it first. This can be done with the following command:
import { MemcachedCache } from "pip-services4-memcached-node";
import (
memcache "github.com/pip-services4/pip-services4-go/pip-services4-memcached-go/cache"
)
from pip_services4_memcached.cache import MemcachedCache
Component creation
Once we have imported our base class, we instantiate and configure it. Our main configuration parameters are the connection host and the port. In our case, we use our machine and the default port for Memcached. The following code explains how to do this:
import { ConfigParams } from "pip-services4-components-node";
import { MemcachedCache } from "pip-services4-memcached-node";
let cache = new MemcachedCache();
cache.configure(ConfigParams.fromTuples(
"connection.host", "localhost",
"connection.port", 11211
));
import (
"context"
conf "github.com/pip-services4/pip-services4-go/pip-services4-components-go/config"
memcache "github.com/pip-services4/pip-services4-go/pip-services4-memcached-go/cache"
)
cache := memcache.NewMemcachedCache[any]()
cache.Configure(context.Background(), conf.NewConfigParamsFromTuples(
"connection.host", "localhost",
"connection.port", 11211,
))
cache = MemcachedCache()
from pip_services4_components.config import ConfigParams
from pip_services4_components.context import Context
cache.configure(ConfigParams.from_tuples(
"connection.host", "localhost",
"connection.port", 11211
))
context_data = {
"traceId": "123",
}
my_context = Context(context_data)
Once we have our component, we can connect it to our Memcached store through the open() method. This method requires a context as input parameter only.
await cache.open(ctx);
cache.Open(context.Background())
cache.open(my_context)
CRUD operations
The MemcachedCache class offers several methods to perform CRUD operations. They are:
Create and update
The store() method can be used to create a record or update its values if the record already exists. This method accepts the context, the key and value, and the timeout as input parameters. It returns True if the operation was successful, and False otherwise. The following example explains its syntax:
await cache.store(ctx, "key1", "ABC", 5000); // Returns True if successful and False otherwise.
res, err := cache.Store(context.Background(), "key1", "ABC", 5000)
cache.store(my_context, "key1", "ABC", 5000) # Returns True if successful and False otherwise.
Read
The retrieve() method can be used to obtain a stored record according to a given key. The following example describes its usage.
var value = await cache.RetrieveAsync<string>(ctx, "key1"); // Returns "ABC"
value, err := cache.Retrieve(context.Background(), "key1") // Returns "ABC"
value = cache.retrieve(my_context, "key1", ) # Returns "ABC"
Delete
We can use the remove() method to delete a record, which asks for a context and a key as input parameters. An example of its syntax is:
await cache.remove(ctx, "key1"); // Returns True if successful and False otherwise
cache.Remove(context.Background(), "key1") // Retruns: an error or nil for success
cache.remove(my_context,'key1') # Returns True if successful and False otherwise
MemcachedLock
This component allows us to create distributed locks based on Memcached caching and contains several functions for managing them. The next sections explain how to use it.
Pre-requisites
Before using it, we need to import this class. The following command shows how to do this:
import { MemcachedLock } from "pip-services4-memcached-node";
import (
memlock "github.com/pip-services4/pip-services4-go/pip-services4-memcached-go/lock"
)
from pip_services4_memcached.lock import MemcachedLock
Component creation
To create a lock, we need to create an instance of this class and configure it with our database’s connection parameters. The following example connects to a Memcached store located in our machine and through the default port 11211.
import { ConfigParams, IContext } from "pip-services4-components-node";
import { MemcachedLock } from "pip-services4-memcached-node";
let lock = new MemcachedLock();
lock.configure(ConfigParams.fromTuples(
"connection.host", "localhost",
"connection.port", 11211
));
import (
"context"
conf "github.com/pip-services4/pip-services4-go/pip-services4-components-go/config"
memlock "github.com/pip-services4/pip-services4-go/pip-services4-memcached-go/lock"
)
lock := memlock.NewMemcachedLock()
lock.Configure(context.Background(), conf.NewConfigParamsFromTuples(
"connection.host", "localhost",
"connection.port", 11211,
))
lock = MemcachedLock()
from pip_services4_components.config import ConfigParams
from pip_services4_components.context import Context
lock.configure(ConfigParams.from_tuples(
"connection.host", "localhost",
"connection.port", 11211
))
context_data = {
"traceId": "123",
}
my_context = Context(context_data)
After defining our lock, we connect it to our Memcached store via the open() command.
await lock.open(ctx);
lock.Open(context.Background())
lock.open(my_context)
Managing the lock
Now, we can use our lock. For this, we have two primary operations: acquire and release, which can be managed with a set of methods available in this class.
Acquire
To acquire a lock, we have two methods. They are:
tryAcquireLock()
This method makes a single attempt at acquiring a lock. It asks for a context, a key, and a timeout value in milliseconds as input parameters. It returns True if the operation was successful, and False otherwise.
await lock.tryAcquireLock(ctx, "key3566", 34000); // Returns True is successful and False otherwise
lock.TryAcquireLock(context.Background(), "key3566", 34000) // Returns True is successful and False otherwise and err obj
lock.try_acquire_lock(my_context, "key3566", 34000) # Returns True is successful and False otherwise
acquireLock()
This method makes multiple attempts at acquiring a log. It accepts a context, a key, a timeout, and a lock acquisition timeout in milliseconds as input parameters. The following example shows how to use it.
await lock.acquireLock(ctx, "key1", 3000, 1000);
lock.AcquireLock(context.Background(), "key1", 3000, 1000)
lock.acquire_lock(my_context, "key1", 3000, 1000)
Release
Once used, we can release the lock with the releaseLock() method, which takes a context and a key as input parameters. Its usage is as follows:
await lock.releaseLock(ctx, "key1");
lock.ReleaseLock(context.Background(), "key1")
lock.release_lock(my_context, "key1")
Example
Now that we understand how to create and manage a MemcachedLock, we can summarize all the operations in one example. In it, we create an instance of the component, configure it and connect to Memcached. We use a local store and the default port.
Then, we acquire the lock and perform some operations. Once the processing is done, we release the lock. Our code looks something like this:
import { ConfigParams, IContext } from "pip-services4-components-node";
import { MemcachedLock } from "pip-services4-memcached-node";
export async function main() {
var lock = new MemcachedLock();
lock.configure(ConfigParams.fromTuples(
"connection.host", "localhost",
"connection.port", 11211
));
// ...
await lock.open(ctx);
await lock.acquireLock(ctx, "key1", 3000, 1000);
try {
// Processing...
}
finally {
await lock.releaseLock(ctx, "key1");
}
await lock.close(ctx);
}
import (
"context"
conf "github.com/pip-services4/pip-services4-go/pip-services4-components-go/config"
memlock "github.com/pip-services4/pip-services4-go/pip-services4-memcached-go/lock"
)
func main() {
lock := memlock.NewMemcachedLock()
lock.Configure(context.Background(), conf.NewConfigParamsFromTuples(
"connection.host", "localhost",
"connection.port", 11211,
))
lock.Open(context.Background())
defer lock.Close(context.Background())
lock.AcquireLock(context.Background(), "key1", 3000, 1000)
defer lock.ReleaseLock(context.Background(), "key1")
// Processing...
}
from pip_services4_memcached.lock import MemcachedLock
from pip_services4_components.config import ConfigParams
from pip_services4_components.context import Context
lock = MemcachedLock()
lock.configure(ConfigParams.from_tuples(
"connection.host", "localhost",
"connection.port", 11211
))
context_data = {
"traceId": "123",
}
my_context = Context(context_data)
lock.open(my_context)
lock.acquire_lock(my_context, "key1", 3000, 1000)
try:
# Processing...
pass
finally:
lock.release_lock(my_context, "key1")
lock.close(my_context)
Wrapping up
This tutorial taught us how to create distributed caches and locks using a Memcached store. First, we learned how to define our cache and perform CRUD operations on records stored in our cache. Then, we created a distributed lock and saw how to manage it. We finished the explanations with an example that showed how to practically use a MemcachedLock with a processing task.