11# Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
22
33import threading
4- from abc import ABC
54from typing import List , Mapping , Optional , Tuple , TypeVar , Union
65
76from deprecated import deprecated
6160TBatch = TypeVar ("TBatch" , bound = "BaseBatch" )
6261
6362
64- class BaseBatch ( ABC ) :
63+ class BaseBatch :
6564 """
66- Base class encompassing shared commands for both standalone and cluster mode implementations in batch.
67-
68- See [Transactions](https://valkey.io/topics/transactions/) and
69- [Pipelines](https://valkey.io/topics/pipelines/) for details.
65+ Base class encompassing shared commands for both standalone and cluster server installations.
66+ Batches allow the execution of a group of commands in a single step.
7067
7168 Batch Response:
72- The response for each command depends on the executed command. Specific response types
73- are documented alongside each method.
69+ An ``array`` of command responses is returned by the client ``exec`` command, in the order they were given.
70+ Each element in the array represents a command given to the batch.
71+ The response for each command depends on the executed Valkey command.
72+ Specific response types are documented alongside each method.
7473
7574 Args:
7675 is_atomic (bool): Determines whether the batch is atomic or non-atomic.
77- If `True`, the batch will be executed as an atomic transaction.
78- If `False`, the batch will be executed as a non-atomic pipeline.
79- See [Valkey Transactions](https://valkey.io/topics/transactions/) and
80- [Valkey Pipelines](https://valkey.io/topics/pipelines/) for more details.
76+ If ``True``, the batch will be executed as an atomic transaction.
77+ If ``False``, the batch will be executed as a non-atomic pipeline.
78+
79+ See [Transactions](https://valkey.io/topics/transactions/) and [Pipelines](https://valkey.io/topics/pipelines/) for details.
80+
8181 """
8282
8383 def __init__ (self , is_atomic : bool ) -> None :
84+ """
85+ Args:
86+ is_atomic (bool): Determines whether the batch is atomic or non-atomic.
87+ If `True`, the batch will be executed as an atomic transaction.
88+ If `False`, the batch will be executed as a non-atomic pipeline.
89+ """
8490 self .commands : List [Tuple [RequestType .ValueType , List [TEncodable ]]] = []
8591 self .lock = threading .Lock ()
8692 self .is_atomic = is_atomic
@@ -278,7 +284,7 @@ def custom_command(self: TBatch, command_args: List[TEncodable]) -> TBatch:
278284 Example:
279285 Append a command to list of all pub/sub clients:
280286
281- >>> transaction .customCommand(["CLIENT", "LIST","TYPE", "PUBSUB"])
287+ >>> batch .customCommand(["CLIENT", "LIST","TYPE", "PUBSUB"])
282288 """
283289 return self .append_command (RequestType .CustomCommand , command_args )
284290
@@ -366,7 +372,7 @@ def config_set(
366372 Command response:
367373 OK: Returns OK if all configurations have been successfully set.
368374
369- Otherwise, the transaction fails with an error.
375+ Otherwise, the command fails with an error.
370376 """
371377 parameters : List [TEncodable ] = []
372378 for pair in parameters_map .items ():
@@ -401,8 +407,10 @@ def mset(self: TBatch, key_value_map: Mapping[TEncodable, TEncodable]) -> TBatch
401407 and the keys in `key_value_map` map to different hash slots,
402408 the command will be split across these slots and executed separately for each.
403409 This means the command is atomic only at the slot level.
404-
405- See [valkey.io](https://valkey.io/commands/mset/) for more details.
410+ If one or more slot-specific requests fail, the entire call will return the first encountered error, even
411+ though some requests may have succeeded while others did not.
412+ If this behavior impacts your application logic, consider splitting the
413+ request into sub-requests per slot to ensure atomicity.
406414 """
407415 parameters : List [TEncodable ] = []
408416 for pair in key_value_map .items ():
@@ -448,6 +456,10 @@ def mget(self: TBatch, keys: List[TEncodable]) -> TBatch:
448456 In cluster mode, if this command is used in a non-atomic batch (pipeline)
449457 and the keys map to different hash slots, the command will be split across these slots
450458 and executed separately for each. This means the command is atomic only at the slot level.
459+ If one or more slot-specific requests fail, the entire call will return the first encountered error, even
460+ though some requests may have succeeded while others did not.
461+ If this behavior impacts your application logic, consider splitting the
462+ request into sub-requests per slot to ensure atomicity.
451463 """
452464 return self .append_command (RequestType .MGet , keys )
453465
@@ -473,7 +485,7 @@ def config_rewrite(self: TBatch) -> TBatch:
473485
474486 Command response:
475487 OK: OK is returned when the configuration was rewritten properly.
476- Otherwise, the transaction fails with an error.
488+ Otherwise, the command fails with an error.
477489 """
478490 return self .append_command (RequestType .ConfigRewrite , [])
479491
@@ -752,7 +764,7 @@ def hlen(self: TBatch, key: TEncodable) -> TBatch:
752764 Command response:
753765 int: The number of fields in the hash, or 0 when the key does not exist.
754766
755- If `key` holds a value that is not a hash, the batch fails with an error.
767+ If `key` holds a value that is not a hash, the command fails with an error.
756768 """
757769 return self .append_command (RequestType .HLen , [key ])
758770
@@ -5294,30 +5306,40 @@ def sort_store(
52945306
52955307class Batch (BaseBatch ):
52965308 """
5297- Extends BaseBatch class for standalone commands that are not supported in cluster mode.
5309+ Batch implementation for standalone GlideClient. Batches allow the execution of a group
5310+ of commands in a single step.
52985311
5299- Command Response:
5300- The response for each command depends on the executed command. Specific response types
5301- are documented alongside each method.
5312+ Batch Response:
5313+ An ``array`` of command responses is returned by the client ``exec`` command,
5314+ in the order they were given. Each element in the array represents a command given to the Batch.
5315+ The response for each command depends on the executed Valkey command.
5316+ Specific response types are documented alongside each method.
5317+
5318+ Args:
5319+ is_atomic (bool): Determines whether the batch is atomic or non-atomic. If ``True``,
5320+ the batch will be executed as an atomic transaction. If ``False``,
5321+ the batch will be executed as a non-atomic pipeline.
5322+
5323+ See [Transactions](https://valkey.io/topics/transactions/) and [Pipelines](https://valkey.io/topics/pipelining/) for details.
53025324
53035325 Note for Standalone Mode (Cluster Mode Disabled):
53045326 Standalone Batches are executed on the primary node.
53055327
5306- Transaction Example:
5307- >>> transaction = Batch(is_atomic=True)
5328+ Example (Atomic Batch - Transaction) :
5329+ >>> transaction = Batch(is_atomic=True) # Atomic (Transaction)
53085330 >>> transaction.set("key", "value")
5309- >>> transaction.select(1) # Standalone command
53105331 >>> transaction.get("key")
5311- >>> await client.exec(transaction)
5312- [OK , OK , None]
5313-
5314- Pipeline Example:
5315- >>> pipeline = Batch(is_atomic=True)
5316- >>> pipeline.set("key", "value")
5317- >>> pipeline.select(1) # Standalone command
5318- >>> pipeline.get("key")
5319- >>> await client.exec(pipeline)
5320- [OK , OK , None]
5332+ >>> result = await client.exec(transaction)
5333+ >>> assert result == [OK, b"value"]
5334+
5335+ Example (Non-Atomic Batch - Pipeline):
5336+ >>> pipeline = Batch(is_atomic=False) # Non-Atomic (Pipeline)
5337+ >>> pipeline.set("key1", "value1")
5338+ >>> pipeline.set("key2", "value2")
5339+ >>> pipeline.get("key1")
5340+ >>> pipeline.get("key2")
5341+ >>> result = await client.exec(pipeline)
5342+ >>> assert result == [OK, OK, b"value1", b"value2"]
53215343 """
53225344
53235345 # TODO: add SLAVEOF and all SENTINEL commands
@@ -5408,14 +5430,38 @@ def publish(self, message: TEncodable, channel: TEncodable) -> "Batch":
54085430
54095431class ClusterBatch (BaseBatch ):
54105432 """
5411- Extends BaseBatch class for cluster mode commands that are not supported in standalone.
5433+ Batch implementation for cluster GlideClusterClient. Batches allow the execution of a group
5434+ of commands in a single step.
54125435
5413- Command Response:
5414- The response for each command depends on the executed command. Specific response types
5415- are documented alongside each method.
5436+ Batch Response:
5437+ An ``array`` of command responses is returned by the client ``exec`` command,
5438+ in the order they were given. Each element in the array represents a command given to the ClusterBatch.
5439+ The response for each command depends on the executed Valkey command.
5440+ Specific response types are documented alongside each method.
5441+
5442+ Args:
5443+ is_atomic (bool): Determines whether the batch is atomic or non-atomic. If ``True``,
5444+ the batch will be executed as an atomic transaction. If ``False``,
5445+ the batch will be executed as a non-atomic pipeline.
5446+
5447+ See [Transactions](https://valkey.io/topics/transactions/) and [Pipelines](https://valkey.io/topics/pipelining/) for details.
5448+
5449+ Example (Atomic Batch - Transaction) in a Cluster:
5450+ >>> transaction = ClusterBatch(is_atomic=True) # Atomic (Transaction)
5451+ >>> transaction.set("key", "value")
5452+ >>> transaction.get("key")
5453+ >>> result = await client.exec(transaction)
5454+ >>> assert result == [OK, b"value"]
5455+
5456+ Example (Non-Atomic Batch - Pipeline) in a Cluster:
5457+ >>> pipeline = ClusterBatch(is_atomic=False) # Non-Atomic (Pipeline)
5458+ >>> pipeline.set("key1", "value1")
5459+ >>> pipeline.set("key2", "value2")
5460+ >>> pipeline.get("key1")
5461+ >>> pipeline.get("key2")
5462+ >>> result = await client.exec(pipeline)
5463+ >>> assert result == [OK, OK, b"value1", b"value2"]
54165464
5417- When the client is configured to read from replicas, read commands
5418- in a non-atomic batches will be distributed in a round-robin manner across the replicas.
54195465 """
54205466
54215467 def copy (
0 commit comments