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 for example.
To get some context, here’s the overall logic of the plugin:
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:
- I tried to use
response()
instead oflog()
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 usinglog()
? - In
log()
I wasn’t able to use the database. I found this thread. I used atimer
and it worked, but I don’t really understand why, can anyone enlighten me?
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
- To make it work, I needed to call
kong.service.request.enable_buffering()
inaccess
. I couldn’t find the potential issues of doing that in the documentation, are there any? - 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?
local body
if ngx.status < 500 then
body = kong.service.response.get_raw_body()
end
- 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)
inaccess()
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