cgi.d's new scheduler, static this tricks
Posted 2019-08-05
Blog
Articles- terminal.d gets clipboard functions, ldc 1.20 out.
- DConf keynote speaker announced: Lua architect Roberto Ierusalimschy, Named args DIP discussed
- February 3, 2020
- Adam's terminal suite explained
- Understanding mixin templates, terminal.d improvements
- My attribute-by-default proposal. Also dmd 2.090 came out.
- DConf 2020 announced: June 17-20 in London. @safe by default debated. Adam did: Android, JNI, WebSocket in arsd libs
- tar.xz, --DRT tip, dom bug fixes, more Android and JNI, link to old phobos docs
- LDC 1.19 - Android, AVR. My rant on tests, update on JNI and COM.
- Walter's string interpolation proposal is OK but not great. My Android thing nearing beta release. dub downtime explained.
- Android project update, introduction to arsd.jni
- New pattern about interface contracts
- Adam shares Windows console secrets - DO NOT USE chcp!!
- Adam's rant on benchmarks
- Socket tutorial
- November 4, 2019
- October 28, 2019
- arsd package updates, forum nonsense
- Update on Android
- Adam does iOS "goodbye world"
- September 30, 2019
- D turns 20, Adam rants on software freedom
- Named arg DIPs and my thoughts on code organization
- September 9, 2019
- I wrote about mixin templates vs string mixins on Stack Overflow
- August 26, 2019
- Bug bounty in D again - my hot take, on reusing code, a fun picture, my tentative plan for the next month
- Time invested is worth a lot
- cgi.d's new scheduler, static this tricks
- July 29, 2019
- July 22, 2019
- Solving vs managing problems
- A big week in the arsd repo
- July 1, 2019
- June 24, 2019
- June 17, 2019
- CRTP thoughts, named arguments DIP review, DConf videos now on youtube
- musings on hybrid CT/RT tests, some more progress on new web framework
- a little more webassembly
- May 20, 2019
- Adam's string interpolation proposal
- DMD 2.086 live, GCC 9 with D support formally released, DConf coming soon, links to posts on builder pattern and disallowing implicit conversions with templates, and 2d array op overloads
- template constraint error improvements coming?
- dmd 2.086 beta, dstep 1.0 released, Adam works on memory usage
- obj-c and webassembly report, tips on is expressions linked.
- new ldc, new dmd, dpp on the blog
- D's future discussed in forums
- LDC beta, DConf blog link, Adam introduces gamehelpers.d
- March 18, 2019
- LDC 1.15.0-beta1, responsive design rant
- dmd 2.085.0 released
- Obj-C interop and D without druntime code to copy/paste
- dmd beta, more info coming next time, demo of new web framework initial prototype
- automatic web interface discussion, reflection tips and tricks
- Adam busy with weather and a move, lots of community announcements
- January 28, 2019
- Working on official blog 2018 retro, C++ new wrapped, dmd reading zips?
- dmd obj-c growing, Adam static foreaches an interface to RPC
- dmd 2.084, hope for future, but busy non-D week for me
- IDE tools released, my cgi.d gets new features
- DConf announced, tip, Adam rants: mouse trap
- This Week in D is back!
This week, I wrote a new schedule server. Below, I describe how it works.
BTW in other news, there's some cool new stuff coming out in dmd - better template error messages, and getLocation for better custom errors. Next release is exciting to me!
Core D Development Statistics
In the community
Community announcements
See more at the announce forum.
What Adam is working on
I first talked about this several months ago, but just now finally implemented the code for the schedule server in cgi.d. The usage code looks like this:
On the inside, the schedule function gathers arguments and puts them into a ScheduledJobHelper struct. This struct contains the methods to do the scheduling itself - asap, delay, and at right now. These communicate with the timer server, which is embedded in the arsd.cgi library, and currently run separately via ./yourprogram --timer-server. I'll probably have it run automatically later on demand, or possibly run in a helper thread of your application depending on build flags.
The timer server will wait until the specified time - on Linux, via the timerfd mechanism, so the kernel is responsible for waking the program up when the time has come - and then call the function in a new process via shell execute.
There are a few tricks in the implementation I'd like to show you all:
This isn't great, I kinda wish the D language had some kind of "must use return value" indicator we can put on a function.
In this implementation, the schedule function actually creates a shared static this constructor:
This is a long-form eponymous template. It is called like any other function - as you saw above - but also includes the second declaration, the shared static this constructor.
The compiler will automatically combined all these static constructors into one at the end of the build, meaning you can call this as many times as you want, in as many different places as you want, and it will all initialize that single scheduledJobHandlers array at runtime! Even the immutable part just works, since the compiler treats the many as one. e plubrius unum lol.
Now, when the program runs, it can look up the function in that associative array and run it!
Hence we see what the timer scheduler does: it just calls your_application --timed-job mangle_here args go here... and it then looks it up in that array. This gives it flexibility for use by several different applications, all cgi modes, crash resilience, and easy use manually from the command line too. In theory (but not implemented), I can also make a management interface to see the waiting background/timed jobs.
This lets us gather compile time info into one place without an explicit registration step.
But alas, no such thing exists, so I just warn in the documentation instead.
Which is inside the schedule function. That function is never run... so why is it there?
That's a hack to get some type checking and decent error messages for the forwarded argument list. I could use if(__traits(compiles(fn(args)))), but then you lose detailed error messages. I want it to act like a regular function call, so I had to compile one normally.
The only weird thing is I don't actually want to call it *here*, hence wrapping it in a function that is never called.
Well, there's a few places where I wish D could do a bit more, but it is still pretty cool that it does that it does so easily.