{
  "id": "Uu9WHIVYDxZZGRfn",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Debouncer",
  "tags": [],
  "nodes": [
    {
      "id": "2b05b9b8-1345-433c-89ae-e661e4fbed73",
      "name": "Crypto",
      "type": "n8n-nodes-base.crypto",
      "position": [
        832,
        0
      ],
      "parameters": {
        "action": "generate"
      },
      "typeVersion": 1
    },
    {
      "id": "76fa3e75-d0bd-4fcb-a5c0-ee6d4e75c9b8",
      "name": "Set last update uuid",
      "type": "n8n-nodes-base.redis",
      "position": [
        1040,
        0
      ],
      "parameters": {
        "key": "=last_update_{{$('Trigger').item.json.queue_id}}",
        "value": "={{ $json.data }}",
        "keyType": "string",
        "operation": "set"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "3e11b11a-7dd5-4da0-a235-131bc5e6f560",
      "name": "Push to message list",
      "type": "n8n-nodes-base.redis",
      "position": [
        624,
        0
      ],
      "parameters": {
        "list": "=messages_{{ $('Trigger').item.json.queue_id }}",
        "tail": true,
        "operation": "push",
        "messageData": "={{ $('Trigger').item.json.data }}"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4d658d52-7263-4fe8-a33c-95205a428ee2",
      "name": "Get last update uuid",
      "type": "n8n-nodes-base.redis",
      "position": [
        1456,
        0
      ],
      "parameters": {
        "key": "=last_update_{{$('Trigger').item.json.queue_id}}",
        "keyType": "string",
        "options": {},
        "operation": "get"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "c4e6a9f2-6cb6-4f95-b379-87abcfd28ef1",
      "name": "Am I last?",
      "type": "n8n-nodes-base.if",
      "position": [
        1664,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "5f079d57-28f5-4c65-b923-bda948386a3d",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $('Crypto').item.json.data }}",
              "rightValue": "={{ $json.propertyName }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "b591d68b-7652-47c3-8efd-7149171fc759",
      "name": "Set lock",
      "type": "n8n-nodes-base.redis",
      "position": [
        736,
        224
      ],
      "parameters": {
        "key": "=lock_{{ $('Trigger').item.json.queue_id }}",
        "operation": "incr"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "c58ef873-7192-408c-a2bc-e16bf9ba9951",
      "name": "Get messages",
      "type": "n8n-nodes-base.redis",
      "position": [
        944,
        224
      ],
      "parameters": {
        "key": "=messages_{{ $('Trigger').item.json.queue_id }}",
        "keyType": "list",
        "options": {},
        "operation": "get",
        "propertyName": "data"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "ebde1acc-acd4-458c-b0e6-a565fa72afa2",
      "name": "Clear messages",
      "type": "n8n-nodes-base.redis",
      "position": [
        1152,
        224
      ],
      "parameters": {
        "key": "=messages_{{ $('Trigger').item.json.queue_id }}",
        "operation": "delete"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "fb31c660-1bf8-410b-b62e-0d54ccd4a424",
      "name": "Release lock",
      "type": "n8n-nodes-base.redis",
      "position": [
        1360,
        224
      ],
      "parameters": {
        "key": "=lock_{{ $('Trigger').item.json.queue_id }}",
        "operation": "delete"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "37fdccf4-c94b-47bd-ae6d-98595aa538ab",
      "name": "Get lock value",
      "type": "n8n-nodes-base.redis",
      "position": [
        208,
        0
      ],
      "parameters": {
        "key": "=lock_{{ $('Trigger').item.json.queue_id }}",
        "keyType": "string",
        "options": {},
        "operation": "get",
        "propertyName": "data"
      },
      "credentials": {
        "redis": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f5bf455d-da4d-40ae-8022-5862328b1605",
      "name": "Is lock active?",
      "type": "n8n-nodes-base.if",
      "position": [
        416,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "a1b9e7c6-e5e7-4e1e-89df-6253a2814237",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.data }}",
              "rightValue": 0
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.2
    },
    {
      "id": "349943c9-0eeb-4bac-a421-69edf80980a2",
      "name": "Wait for lock release",
      "type": "n8n-nodes-base.wait",
      "position": [
        416,
        224
      ],
      "parameters": {
        "amount": 1
      },
      "typeVersion": 1.1
    },
    {
      "id": "dfa71544-cd5f-4641-b8b1-c5e56cecdcfc",
      "name": "Split messages",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        1568,
        224
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "data"
      },
      "typeVersion": 1
    },
    {
      "id": "025c1d50-6119-4533-af70-3d22621ebf89",
      "name": "Trigger",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "workflowInputs": {
          "values": [
            {
              "name": "queue_id"
            },
            {
              "name": "data"
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "26455d70-c6d6-43f8-86e7-3d94703f327e",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -544,
        -160
      ],
      "parameters": {
        "width": 480,
        "height": 848,
        "content": "# Generic debouncer\n\nThis is a generic debouncer system implementation built using Redis.\n\n## How it works\nThis implementation aggregates incoming data into a Redis list from potentially concurrent workflow executions. It buffers the data for a set period before a single execution retrieves and processes the entire batch.\n\n## Step-by-step Flow:\n\n1. Trigger: Data is received from a trigger (e.g., an external workflow execution).\n\n2. Lock Check: The system verifies that the queue is not currently locked; if it is, the process waits.\n\n3. Append: The received data is appended to a Redis list.\n\n4. Tagging: A unique execution identifier is generated and written to a specific Redis key (acting as a \"last writer\" marker).\n\n5. Wait: The execution pauses for a configured duration.\n\n6. Verification: After the wait, the execution checks if the Redis key still contains its specific identifier.\n\n7. Exit Condition: If the identifier has changed, it indicates a newer execution has arrived. The current execution terminates.\n\n8. Processing: If the identifier matches, this execution assumes responsibility for the batch. It locks the queue, retrieves all data, clears the Redis list, releases the lock, and forwards the aggregated data further."
      },
      "typeVersion": 1
    },
    {
      "id": "4983ab77-7a0c-407d-9a11-56ad002b1f77",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1184,
        -80
      ],
      "parameters": {
        "color": 6,
        "width": 224,
        "height": 224,
        "content": "Debounce period - adjust as needed"
      },
      "typeVersion": 1
    },
    {
      "id": "80ba06f5-44f7-4131-ace1-f41bf5d2a285",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        1248,
        0
      ],
      "parameters": {
        "amount": 2
      },
      "typeVersion": 1.1
    },
    {
      "id": "d04933e6-cffa-4f4a-8f3e-ecb8dc34bc3a",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        128,
        -64
      ],
      "parameters": {
        "color": 6,
        "width": 464,
        "height": 496,
        "content": "Check if this queue's list of messages are being read at the moment"
      },
      "typeVersion": 1
    },
    {
      "id": "860db0b6-737c-4a1c-bc0f-b0543f33fd60",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1776,
        192
      ],
      "parameters": {
        "content": "This will be executed for every message in the queue - connect your futher logic here."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "5df04721-15bb-4b31-9d38-2312792b2514",
  "connections": {
    "Wait": {
      "main": [
        [
          {
            "node": "Get last update uuid",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Crypto": {
      "main": [
        [
          {
            "node": "Set last update uuid",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trigger": {
      "main": [
        [
          {
            "node": "Get lock value",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set lock": {
      "main": [
        [
          {
            "node": "Get messages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Am I last?": {
      "main": [
        [
          {
            "node": "Set lock",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get messages": {
      "main": [
        [
          {
            "node": "Clear messages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Release lock": {
      "main": [
        [
          {
            "node": "Split messages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clear messages": {
      "main": [
        [
          {
            "node": "Release lock",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get lock value": {
      "main": [
        [
          {
            "node": "Is lock active?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split messages": {
      "main": [
        []
      ]
    },
    "Is lock active?": {
      "main": [
        [
          {
            "node": "Wait for lock release",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Push to message list",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get last update uuid": {
      "main": [
        [
          {
            "node": "Am I last?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Push to message list": {
      "main": [
        [
          {
            "node": "Crypto",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set last update uuid": {
      "main": [
        [
          {
            "node": "Wait",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for lock release": {
      "main": [
        [
          {
            "node": "Get lock value",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}