{
  "schema_version": 2,
  "id": "develop/clients/redis-py/transpipe",
  "title": "Pipelines and transactions",
  "url": "https://redis.io/docs/latest/develop/clients/redis-py/transpipe/",
  "summary": "Learn how to use Redis pipelines and transactions",
  "tags": [
    "docs",
    "develop",
    "stack",
    "oss",
    "rs",
    "rc",
    "oss",
    "kubernetes",
    "clients"
  ],
  "last_updated": "2026-08-27T15:55:18+01:00",
  "page_type": "content",
  "content_hash": "48bbf8fac2c1a90efe6cdda8bcab669d143bebd54f5635f2554d906a714efd83",
  "sections": [
    {
      "id": "execute-a-pipeline",
      "title": "Execute a pipeline",
      "role": "content",
      "text": "To execute commands in a pipeline, you first create a pipeline object\nand then add commands to it using methods that resemble the standard\ncommand methods (for example, `set()` and `get()`). The commands are\nbuffered in the pipeline and only execute when you call the `execute()`\nmethod on the pipeline object. This method returns a list that contains\nthe results from all the commands in order.\n\nNote that the command methods for a pipeline always return the original\npipeline object, so you can \"chain\" several commands together, as the\nexample below shows:\n\nFoundational: Use pipelines to batch multiple commands together and reduce network round trips\n\n**Difficulty:** Beginner\n\n**Available in:** Python\n\n##### Python\n\n[code example]"
    },
    {
      "id": "execute-a-transaction",
      "title": "Execute a transaction",
      "role": "content",
      "text": "A pipeline actually executes as a transaction by default (that is to say,\nall commands are executed in an uninterrupted sequence). However, if you\nneed to switch this behavior off, you can set the `transaction` parameter\nto `False` when you create the pipeline:\n\n[code example]"
    },
    {
      "id": "watch-keys-for-changes",
      "title": "Watch keys for changes",
      "role": "content",
      "text": "Redis supports *optimistic locking* to avoid inconsistent updates\nto different keys. The basic idea is to watch for changes to any\nkeys that you use in a transaction while you are processing the\nupdates. If the watched keys do change, you must restart the updates\nwith the latest data from the keys. See\n[Transactions](https://redis.io/docs/latest/develop/using-commands/transactions)\nfor more information about optimistic locking.\n\nThe example below shows how to repeatedly attempt a transaction with a watched\nkey until it succeeds. The code reads a string\nthat represents a `PATH` variable for a command shell, then appends a new\ncommand path to the string before attempting to write it back. If the watched\nkey is modified by another client before writing, the transaction aborts\nwith a `WatchError` exception, and the loop executes again for another attempt.\nOtherwise, the loop terminates successfully.\n\nOptimistic locking: Use WATCH to monitor keys for changes and retry transactions when conflicts occur\n\n**Difficulty:** Intermediate\n\n**Available in:** Python\n\n##### Python\n\n[code example]\n\n\n\nBecause this is a common pattern, the library includes a convenience\nmethod called `transaction()` that handles the code to watch keys,\nexecute the transaction, and retry if necessary. Pass\n`transaction()` a function that implements your main transaction code,\nand also pass the keys you want to watch. The example below implements\nthe same basic transaction as the previous example but this time\nusing `transaction()`. Note that `transaction()` can't add the `multi()`\ncall automatically, so you must still place this correctly in your\ntransaction function.\n\nOptimistic locking with convenience method: Use the transaction() helper to simplify watched transaction patterns\n\n**Difficulty:** Intermediate\n\n**Available in:** Python\n\n##### Python\n\n[code example]"
    }
  ],
  "examples": [
    {
      "id": "execute-a-pipeline-ex0",
      "language": "python",
      "code": "r = redis.Redis(decode_responses=True)\n\npipe = r.pipeline()\n\nfor i in range(5):\n    pipe.set(f\"seat:{i}\", f\"#{i}\")\n\nset_5_result = pipe.execute()\nprint(set_5_result)  # >>> [True, True, True, True, True]\n\npipe = r.pipeline()\n\n# \"Chain\" pipeline commands together.\nget_3_result = pipe.get(\"seat:0\").get(\"seat:3\").get(\"seat:4\").execute()\nprint(get_3_result)  # >>> ['#0', '#3', '#4']",
      "section_id": "execute-a-pipeline"
    },
    {
      "id": "execute-a-transaction-ex0",
      "language": "python",
      "code": "pipe = r.pipeline(transaction=False)",
      "section_id": "execute-a-transaction"
    },
    {
      "id": "watch-keys-for-changes-ex0",
      "language": "python",
      "code": "r.set(\"shellpath\", \"/usr/syscmds/\")\n\nwith r.pipeline() as pipe:\n    # Repeat until successful.\n    while True:\n        try:\n            # Watch the key we are about to change.\n            pipe.watch(\"shellpath\")\n\n            # The pipeline executes commands directly (instead of\n            # buffering them) from immediately after the `watch()`\n            # call until we begin the transaction.\n            current_path = pipe.get(\"shellpath\")\n            new_path = current_path + \":/usr/mycmds/\"\n\n            # Start the transaction, which will enable buffering\n            # again for the remaining commands.\n            pipe.multi()\n\n            pipe.set(\"shellpath\", new_path)\n\n            pipe.execute()\n\n            # The transaction succeeded, so break out of the loop.\n            break\n        except redis.WatchError:\n            # The transaction failed, so continue with the next attempt.\n            continue\n\nget_path_result = r.get(\"shellpath\")\nprint(get_path_result)  # >>> '/usr/syscmds/:/usr/mycmds/'",
      "section_id": "watch-keys-for-changes"
    },
    {
      "id": "watch-keys-for-changes-ex1",
      "language": "python",
      "code": "r.set(\"shellpath\", \"/usr/syscmds/\")\n\n\ndef watched_sequence(pipe):\n    current_path = pipe.get(\"shellpath\")\n    new_path = current_path + \":/usr/mycmds/\"\n\n    pipe.multi()\n\n    pipe.set(\"shellpath\", new_path)\n\n\ntrans_result = r.transaction(watched_sequence, \"shellpath\")\nprint(trans_result)  # True\n\nget_path_result = r.get(\"shellpath\")\nprint(get_path_result)  # >>> '/usr/syscmds/:/usr/mycmds/'",
      "section_id": "watch-keys-for-changes"
    }
  ]
}
