Chris Tankersley

cron-expression Updates and Moving Forward

Posted on 2017-10-12

In late 2015/early 2016, I took over maintenance for the mtdowling/cron-expression library. This was a library that we used at my then day job quite heavily, as it was part of our daily processing and scheduling for customers around the world. It let us schedule cron jobs relative to them, instead of us, without much work. When Michael reached out on Twitter for someone to help maintain it, I jumped at the chance.

For those that do not know what the library does, cron-expression just checks to see if a cron expression (something like 0 0 * * *) is valid, can check to see if it matches the current time and needs to run, and can determine future run dates. If you need a simple way to schedule things, cron itself is a very useful and well understood syntax. cron-expression does not run your code though, it is mostly a validation library.

Much like Sculpin, it's a pretty stable project so there wasn't a ton of movement on it development-wise. Some bug fixes here, few enchancements there, but nothing major. At the beginning of 2017 I pushed out a 1.2.0 release. I had decided that I would only support PHP 7.0 going forward. By this time I had learned that Laravel was using this library under the hood, so I wanted to get one final release done under the older PHP 5.x branch. v2.x and later would all be PHP 7.x compatible.

Then I started digging into a bug, and that bug turned into a few bugs, in regards to validation. As it turns out, the regex that the library used was really loose and let a lot of stuff through. This did not seem to affect valid expressions, but it allowed a lot of junk through. As time went on more and more reports with this started coming through. The underlying logic had to change. I started working on this as the main focus.

Then I got this bug report - #153, "Wrong nextRunDate for * rules". Long story short, step ranges in the library were broken. Someone had discovered a bug in Laravel's cron system that caused the expression to validate on the incorrect set of months. Even I misunderstood how that worked, so I ended up diving into the source code for cronie, one of the main cron systems shipped with Linux systems.

cron-expression had gotten our implementation completely wrong. I re-implemented a bunch of our validation logic to the same basic way that cronie does, and this actually ended up not only fixing our stepping issue but also our data validation woes. The new code was a bit more compact and more unified in how the library does validations. Overall this was good.

There was a big problem though, and that was that this was a huge backward compatibility break. When a bug has survived long enough and people rely on that behavior, it is no longer a bug - it's a feature. So our bad stepping fix has the potentional for breaking a huge number of systems, even if that behavior is bad. People rely on it.

Sufficient time has past for a v2.0.0 release. That will be happening today. All the fixes will be available in packagist as soon as it updates.

The repo will also be moving to a new repository: dragonmantank/cron-expression. The reasons for this are twofold - one, I am not and cannot be the admin of the original repo as it is not an organization, it is a personal repo. I cannot wire in new build or checking systems at all. Two, this is the perfect time to do this break. v2.0.0 is incompatible with v1.0.0 because of the stepping issue, and this will let frameworks or other installs that rely on the v1.x branch to move at their leisure without breaking them.

The old repo will no longer be maintained, but I will still watch the issues. The existing issues will still be evaluated and looked at, just implemented in the new repo. The old package will remain in packagist for those that need it. All new work will be done in the new repo against the 2.x branch.

If anyone has any questions, feel free to hit me up on twitter at @dragonmantank.