Operations¶
A emcache.Client instance provides access to different Memcached operations, we can separate them into two categories:
Storage commands Commands used for storing data to the Memcached server
Fetch commands Commands used for retrieving data from the Memcached server
Following snippet shows how a emcache.Client.set() command can be performed by using a emcache.Client instance:
client = await emcache.create_client(
[emcache.MemcachedHostAddress('localhost', 11211)]
)
await client.set(b"key", b"value")
await client.close()
By default the emcache.Client instance provided by the emcache.create_client() factory comes configured with a default timeout, so if it is not disabled
explicitly any operation might end up raising an asyncio.TimeoutError. As the following snippet
shows a good practice would be wrapping your operations for detecting this use cases for adding any specific logic.
try:
await client.set(b"key", b"value")
except asyncio.TimeoutError:
logging.warning("Set operation timed out, retry?")
Storage commands¶
Emcache has support for the following storage commands:
emcache.Client.set()Save a new key and value.emcache.Client.add()Save a new key and value, if and only if the key does not exist.emcache.Client.replace()Update value to an already existing key.emcache.Client.append()Append a value to the existing value of an already existing key.emcache.Client.prepend()Prepend a value to the existing value of an already existing key.emcache.Client.cas()Update a key and its value using acastoken, if the current key already exists and has a differentcastoken the operation will fail.
Following snippet shows how the emcache.Client.cas() operation can be used:
item = await client.gets(b"key")
await client.cas(b"key", b"new value", item.cas)
Some of the storage commands would need to meet some conditions for finishing successfully, as it is the case of the cas command which requires to
provide a valid cas token or for the case of the emcache.Clientadd() command which wouuld succeed if and only if the key would not exist. In all of these use
cases, when the command execution can not meet the requirements a emcache.NotStoredStorageCommandError is raised. The following
snippet shows how the emcache.Client.cas() command could be wrapped for detecting this kind of situations:
try:
await client.cas(
b"key", b"new value", old_cas_value)
except emcache.NotStoredStorageCommandError:
logging.warning(
"Cas token invalid, key couldn't be updated")
Most of the storage commands come with support for the following flags which they are exposed as keyword arguments for each of the operations:
flags Store an
int16value along with the value of the key, later on, this flags can be retrieved by the fetch commandsexptime Expiration time of the key. By setting this value, with an absolute timestamp, the Memcached server will consider the key evicted
noreply Do not wait for a confirmation from the Memcached server, fire and forget. You won’t know if the operation finished successfully.
Following snippet shows how the emcache.Client.set() command can be used for using the different flags explained above:.
await client.set(
b"key", b"value",
flags=4,
# Expire in one hour
exptime=int(time.time()) + 3600,
# Do not ask for an explicit reply from Memcached
noreply=True
)
Fetch commands¶
Fetch commands provide a way for retrieving data that has been saved before by using one of the storage commands that we have seen, emcache.Client provides
the following methods for retrieving data from a Memcached server:
emcache.Client.get()Return value related with a key.emcache.Client.gets()Return a value and thecastoken related with a key.emcache.Client.get_many()Return a set of values related to a set of keys.emcache.Client.gets_many()Return a set of values and theircastokens related to a set of keys.
Emcahe returns values as an instance of an emcache.Item object which has the following attributes:
emcache.Item.valueValue of the key.emcache.Item.cascastoken of the key.emcache.Item.flagsflags of the key.
Methods emcache.Client.get() and emcache.Client.get_many() would return emcache.Item instances with only
the attr:emcache.Item.value set, and having the other ones left to None, as can be seen in the following example:
item = await client.get(b"key")
assert item.value is not None
assert item.cas is None
assert item.flags is None
For having access to the flags, the return_flags keyword would need to be set to True. For retrieving the cas token the
emcache.Client.gets() or emcache.Client.gets_many() methods would need to be used, as can be seen in the following example:
item = await client.gets(b"key", return_flags=True)
assert item.value is not None
assert item.cas is not None
assert item.flags is not None
The emcache.Client.gets_many() and emcache.Client.get_many() operations return a dictionary of the keys found, having as a value
the emcache.Item of each key. For example:
await for key, item in client.get_many([b"key", b"key2"]).items():
print(f"Key {key} found with value {item.value}")
Both methods might end up sending different commands to different nodes, depending on the outcome of the hashing algorithm. If this is the case, the operation will give up completely in case of any error, raising an exception with the error and canceling the ongoing requests.
Other commands¶
Emcache has also support for the following other commands:
emcache.Client.increment()Increases an already existing key by a value.emcache.Client.decrement()Decreases an already existing key by a value.emcache.Client.touch()Overrides the expiration time of an already existing key.emcache.Client.delete()Deletes an existing key.emcache.Client.flush_all()Flush all keys from an existing node, see notes below.
The emcache.Client.flush_all() method targets a specific node, so the parameter expected is the emcache.MemcachedHostAddress() which
identifies univocally a memcached host within the cluster. Also, a parameter called delay is supported for telling to the Memcached server that the
expiration of all of the keys should be done after a specific period of time. This option allows for example to delay the expiration of the keys
for each node in a different moment of time, which should help you on the way for mitigating the likely load that underlying resources might get because
of the increase of misses.
As an example, the following snippet shows how emcache.Client.flush_all() can be used:
hosts = [
emcache.MemcachedHostAddress('localhost', 11211),
emcache.MemcachedHostAddress('localhost', 11212)
]
for idx, host in enum(hosts):
await client.flush_all(host, delay=10 + (10*idx))