# Question on my implementation of an idempotency plugin

**URL:** <https://discuss.konghq.com/t/question-on-my-implementation-of-an-idempotency-plugin/10324>\
**Category:** Questions\
**Created:** [June 24, 2022, 9:27am UTC](https://discuss.konghq.com/t/question-on-my-implementation-of-an-idempotency-plugin/10324 "2022-06-24T09:27:02Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Joan\_Zapata](https://yyz2.discourse-cdn.com/flex036/user_avatar/discuss.konghq.com/joan_zapata/32/3499_2.png) [@Joan\_Zapata](https://discuss.konghq.com/u/Joan_Zapata)\
**Post date:** [June 24, 2022, 9:27am UTC](https://discuss.konghq.com/t/question-on-my-implementation-of-an-idempotency-plugin/10324/1 "2022-06-24T09:27:02Z")

</div>

Hello,

I’ve implemented a custom plugin but I needed to do some hacking to achieve what I wanted. Being a beginner with Nginx and Kong, I’d very much like some opinion on whether this is OK or not.

Basically, my plugin stores the response of requests based on a `Idempotency-Key` header and replays them in case the same key is reused on a subsequent request. I’m trying to achieve the same kind of behaviour you can see on [Stripe](https://stripe.com/docs/api/idempotent_requests) for example.

To get some context, here’s the overall logic of the plugin:

```auto
function MyHandler:access()
  -- Retrieve Idempotency-Key header
  -- If already used, resend previous response immediately.
  -- If not, store an entity in DB in a "pending" state.
end

function MyHandler:log()
  -- Store the response status and body in DB on the entity, and update state to "completed".
end

```

Now the questions that I have:

1. I tried to use `response()` instead of `log()` first, which seems the most suitable hook, but I realised when upstream server is unavailable, it doesn’t get called, and my entity stays in a “pending” state forever. Did I understand well? Was there a better option than using `log()`?
2. In `log()` I wasn’t able to use the database. I found [this thread](https://discuss.konghq.com/t/api-disabled-in-the-context-of-log-by-lua-unable-to-perform-database-action-as-well-tcp-connection-in-log-header-filter-body-filter-modules-in-my-custom-plugin/4497). I used a `timer` and it worked, but I don’t really understand why, can anyone enlighten me?

```auto
function MyHandler:log()
  
  local saved = {
    ngx_ctx = ngx.ctx,
    idempotency_key_header = idempotency_key_header,
    credential_id = credential_id,
    response_body = kong.service.response.get_raw_body(),
    response_status = ngx.status,
  }

  ngx.timer.at(0, function()
    ngx.ctx.KONG_PHASE = saved.ngx_ctx.KONG_PHASE
    -- Access DB from here
  end
end

```

1. To make it work, I needed to call `kong.service.request.enable_buffering()` in `access`. I couldn’t find the potential issues of doing that in the documentation, are there any?
2. In `logs()`, when upstream is down or there’s a timeout contacting it, there’s no body to read and it fails. I compensated by only reading responses below status 500. Do you think there’s a better condition to use here, like is there a flag like “upstream didn’t answer” somewhere in the context?

```auto
  local body
  if ngx.status < 500 then
    body = kong.service.response.get_raw_body()
  end

```

1. Finally, I noticed that conveniently, even though I couldn’t read the body of a 502 error for example, I didn’t need to, because returning `kong.response.exit(502, nil)` in `access()` will actually add the same body later on. Is that a documented behaviour I can rely on?

Thanks for reading, sorry that’s a lot of question, feel free to answer partially, I’m taking every bit of information. 🙂

Cheers,  
Joan
