I'm not a contributor to this project, I'm just chiming in.
There's a lot to nitpick in this code snippet and it would be helpful to see expire_sessions itself. But I think there might be an important pitfall here. It's not likely that your server is "shutting down". Like every database I've worked with in my entire life, MySQL has a timeout to how long a client connection can remain idle before the server decides to close it. You have the option of increasing that timeout server-side, but this won't solve your problem. Here are a few approaches you can take to solve the problem.
- You can create a database connection only when you need it, i.e. do not maintain a connection pool or keep any connections open when MHD workers aren't doing anything. This isn't performant or scalable but it's 100% fault tolerant. Your database can go down, up, disappear and your web app will persist happily. In this context that would mean you create and close the connection entirely within expire_sessions, instead of reusing a connection.
- Or, detect that the reused connection has "gone away" from within expire_sessions, and deal with it on-the-fly. There are two ways you can do this:
- Ping the database before you send any MySQL statement. If the ping fails, throw out the connection and start a new one. Not the most performant but disputably easier to track/debug.
- Or, send your MySQL statement like you're currently doing, but detect the error code or really any connection error, throw out the connection, create a new one, and retry the statement. This is probably the solution you're looking for but requires a significant refactor if you're using the MySQL API directly.
Hope that helps!
On 2023-03-12 10:13 am, klemens wrote:
During longer idle-times of the server, when no queries to mysql happen, mysql is shutting down and the server stops with the message "mysql server has gone away". I try to avoid this by making a "select now()" query every hour or so, but it seems, I can't get out of the eventloop, the func expire_sessions() where the query is done, is never called:
MHD_start_daemon ( 0, 55301, &on_client_connect, myclient_ip, &create_response, NULL, MHD_OPTION_NOTIFY_COMPLETED, &expire_sessions, NULL, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int)120, MHD_OPTION_CONNECTION_LIMIT, (unsigned int)50, MHD_OPTION_END ); if (NULL == vbad) return (emsg ("Can't create daemon")); while (1) { expire_sessions (); max = 0; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); if (MHD_YES != MHD_get_fdset (vbad, &rs, &ws, &es, &max)) break; /* fatal internal error */ if (MHD_get_timeout (vbad, &mhd_timeout) == MHD_YES) { tv.tv_sec = mhd_timeout / 1000; tv.tv_usec = (mhd_timeout - (tv.tv_sec * 1000)) * 1000; tvp = &tv; } else tvp = NULL; if (-1 == select (max + 1, &rs, &ws, &es, tvp)) { if (EINTR != errno) abort (); } MHD_run (vbad);
Could anyone please point out, what I'm doing wrong here. Thanks in advanve.
Klemens.
|