-
Notifications
You must be signed in to change notification settings - Fork 93
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pg:keepalive() should not invalidate the socket reference #46
Conversation
pg:keepalive() calls down to the OpenResty socket connection for reuse in the connection pool, however the reference should still be made available for subsequent calls to pg:connect.
If accepted, maybe this could warrant a regression test to avoid it appearing again? |
On the bright side, it turns out the failing tests I was seeing were due to my build environment. The rockspec file really should have more dependencies defined, e.g., cjson. On the downside, there are no tests for keepalive I can see. This probably makes sense since the connection behavior is different for OpenResty environments than for straight Lua usage. Do you know the differences offhand? (I don't.) |
LuaSocket does not implement any connection pooling mechanism, hence does not implement a 2 approaches: Implement a fallback for it in the You could also rely on the |
not support keepalives.
keepalive is symmetrical to disconnect, the socket reference is deleted to ensure it's not used. I think a better implementation would be to create the socket on the call to |
I was seeing the same thing in the code. When looking more closely at other cosocket projects like redis and memcache, the socket reference is not set to nil. |
I feel like we should rely on the behavior of the underlying socket implementation instead. If Wouldn't that make sense? |
This means that common code that is used both inside and outside of OpenResty would work sometimes and not others vs. having a bunch of if sock_type == "nginx"
-- do something
else
-- do something else in your code. That or a bunch of people rolling their own abstraction layer just for this. It might be more prudent (thinking from the user perspective) to have keepalive() fallback to disconnect() since, as you said @leafo, they have algorithmic symmetry. From the user's perspective, they are interchangeable. The worst that happens is that new socket connections are created instead of being reused, yes? Edit: no, the worst is that an error is returned and a new pg object must be created |
Thank you both for your patience. I'm an old coder, but new to Lua/Moonscript. Still learning the idioms and tooling. |
From the failed tests, I see that cosockets if @sock_type == "nginx" |
I removed the keepalive() test for now. It's only useful for the cosockets case, but the test suite doesn't actually test the cosockets case. Testing the luasocket and cqueues cases seemed odd since they are implementation-specific to another project and not relevant to the use case where keepalive() is actually relevant. Thoughts? |
Yes, hence my previous suggestion of implementing a fallback for LuaSocket. This would have allowed you to:
This is expected of LuaSocket, but shouldn't be the case with cosockets (to be tested). Typical lua-resty libraries try to stay low-level and not abstract too much away from their underlying cosocket(s).
Not familiar with cqueuess which are quite new, but you'd have to implement another fallback or come up with a workaround if that is the case. I don't even know if they implement a connection pool, but if they don't, you can close the connection as well (like LuaSocket). Just my 2c on how I would have done this. |
The cqueues.socket API is markedly different from the others. I can either make them all act roughly the same but hide the some implementation-dependent error types or I can accept that each implementation of sockets will behave differently and give different errors depending on the environment pgmoon is run from. In addition, cqueues.socket always succeeds (in this context) from pg:connect(...) due to hwo its API is handled. By moving the socket connection reference to the connect(...) method, the behavior can be made more uniform, again at the expense of hiding some implementation details/errors. My preference would be following @leafo's suggestion of moving from :new to :connect and making the whole thing more uniform even at the risk of masking what would perhaps be some implementation-specific errors. Thoughts from the veterans since I'm just a newcomer here? I'm happy to follow your lead. |
The problem with this approach (beyond inefficiency) is that you are preventing pgmoon users from the opportunity to sett a granular timeout. The Sure, you could go with new properties such as This is why all those lua-resty-* libraries are usable like simple cosockets, but provide additional methods once they are connected: they stay flexible and allow abstractions to be built on top of them, not within. |
Regarding the timeout granularity thing, it is worth noting the pending PR at openresty/lua-nginx-module#480, that could allow pgmoon to be instantiated with those 3 timeouts attributes, as previously discussed. However, you still need an exposed |
Sounds reasonable to me. So each socket implementation will react differently. With that in mind, keepalive fail for implementations that don't support it? Just return nil with an error for luasocket/cqueue? Seems a bit disingenuous to close the socket without failure message. |
…mplementation doesn't support them. Explicitly test that luasocket and cquque fail this test.
Ping |
@thibaultcha? @leafo? Hello? |
@thibaultcha, it's been a month now |
My 2c: the issue with returning nil + an error message is that now, libraries built on top of this module that want to support all underlying sockets must handle this case on their own; aka not calling |
That's true, but the underlying implementations do not allow for seamless swap out. It's not something a simple proxy can fix. For example, cqueues can use the same reference to connect() again after calling disconnect() while the others cannot. Also, the upstream C queues API can use keepalive while the Lua cqueues implementation does not surface it. And all that's before it gets to pgmoon. The truth is that there is no common path, no safe assumption. Not only is keepalive optional but you can't even be uniform with the definition of db info and the moment of connection—it all varies. The user must know the context the library's used in, and that's leaving aside whether there's anyone out there actually planning on using pgmoon in more than one environment and making the same calls with the same code chunks. |
Bump! I've also been hit by this issue. Without this fix, it seems impossible to recycle a pgmoon instance for multiple connections (neither sockets disconnected via |
Bump. Just got bitten by this issue while writing a fairly simple openresty application. |
Just tried your branch, instead of getting the error from #44 I now got “attempt to receive data on a closed socket”. Any idea? |
Make sure you're only calling keepalive() or disconnect(), never both. |
Alternatively @yangm97, you can install and use pgbouncer for connection pooling. It's what I use. |
So… I got this even without calling keepalive(), disconnect() or settimeout(), leafo:master gives the error from the issue even without calling any of these too. It looks like this only happens when lua code cache is enabled (which explains why I haven’t noticed earlier). The application I’m messing with is an open source fork from GroupButler hosted at https://gitlab.com/Synko/GroupButler/tree/2-webhook-support . content_by_lua requires database.lua, which is a collection of functions made to abstract the SQL complexity, should have SQL injection protections, etc, while not repeating code all over. content_by_lua
database.lua
|
Turns out moving database connection to database.lua fixed the problems from both branches. |
Will this ever be merged? |
pg:keepalive() calls down to the OpenResty socket connection for
reuse in the connection pool, however the reference should still
be made available for subsequent calls to pg:connect.