MODX, PHP & session garbage collection
When did you last check the size of your
modx_session database table? Was it huge, like gigabytes huge? If so, you're not alone.
To understand the problem, you need a little bit of background.
How do sessions work in PHP?
Typically, the standard PHP session handler will create a session when requested, and store it as a simple file somewhere on the system. The path it writes session to is configured with the
session.save_path configuration in the php.ini, and can point anywhere. When that option is empty, it writes to the temp directory on the server.
Creating and loading sessions is simple enough, but the next thing the session handler does is clean up sessions. This is called garbage control, or gc. This removes sessions beyond their expiration time, to make sure it doesn't keep growing indefinitely and takes up your vital disk space.
Garbage control doesn't have to run on every request. If your session/cookie life time is configured to a week and you're not too picky about the exact timing they are removed, then sessions only really need to be checked once a day. Cleaning up sessions can take a little time and resources, so PHP is by default configured to only do that once every 100 requests.
How do sessions work in MODX?
MODX registers a custom session handler that takes care of storing, retrieving, and cleaning up sessions. It writes this to one of its own database tables (
modx_session), rather than files. This allows MODX a little more control over the flow of sessions.
It is also possible to instruct MODX to use standard PHP sessions, and there's also an extra available to write sessions to Redis. But the vast majority of sites will simply be using the default, writing to the database.
So, why does MODX not clean up its session table?
MODX awaits the signal from PHP that it's time to clean up sessions. This relies on 2 configuration options in PHP:
You can find the official documentation for those options here.
Usually the probability is set to 1, and divisor to a value like 100 or 1000. That means that in approximately 1/100 requests, the garbage control will run.
When MODX does not seem to be cleaning up its table, it's usually because of an attempt to improve the performance of the garbage collection, by bypassing PHP and off-loading it to a cron job that runs outside of the request/response cycle.
Those environments assume PHP writes its sessions to a standard location in the filesystem, and clean up that directory based on the timestamp on the file. The
session.gc_probability option is then set to 0, to tell PHP to never run its own session garbage collection.
That works great - if your sessions are written to the standard location. Which MODX doesn't.
How common is this?
Based on data from SiteDash, which checks the size and status of your session table automatically, it's pretty common indeed. Out of a sample of 1727 sites, 27% seem to be affected by this.
How can I fix this?
session.gc_probability. Set it to 1, and make sure
session.gc_divisor is also set properly for your traffic.
Depending on your host and if you have access to a server control panel, you may be able of changing it yourself. In other cases, contact your host and ask them how it should be changed.