Disclaimer: iI have not yet implemented such a system. I see a few clear ways of achieving it but iI have no practical experience with any more caveats invovledinvolved than iI can think of right now.
We first ahvehave to talk about what that event is. If milliseconds matter then the device that triggers the event is also the device that takes the action. Otherwise, networking will be involved. And with networking, second accuracy is the best you can possibly hope for.
Also, the system time of all computers involved in this process must be synchronized with the same accuracy. If your end-users can schedule such events that also involves their computers: there is no point in millisecond accuracy when youreyou're still uncertain for +- 1±1 minute which millisecond it will actually be.
In my experience, millisecond accuracy is far out of reach of interpreted languages/scripting languages. The interpreter will slow you down and you dontdon't have that fine-grained control over CPU cures.
You'll have to at least go as low as Java / .Net. You might get better results with more access to system-level APIs, so D or Go would be options. But all of those have a garbage collector that you'll have to think about. If you use a GCed language you'll have to clean up as much of the memory that you use yourself to avaoidavoid stop-the-world GC events. Doing it yourself is deterministic; you have control about when it happens.
If GCed languages dontdon't yield the accurracyaccuracy that you need, youllyou'll have to go even lower to C / C++ / Rust and similarssimilar languages. You cannot just go ahead and write code in these languages. You'll have to spend time learning to use them properly (shooting yourself in the foot with those languages is far easier than the typical web-programmer thinks - looking at you, Ruby, PHP and NodeJS).
You are only going to get millisecond accuracy when you have exclusive accesaccess to a processing core. And that means one core per timer:
Use a large cluster of microcontrollers on which no other software than yours is running. This will work 100% of the time and you could possibly reach greater precision (maybe .1ms, or even .01ms). But then again, those will have to be able to execute whatever action is associated with the event.
Use machines with multiple cores (e.g. 8 or 16 cores), hope that the OS does not use more than 2 cores and leaves the rest of the cores to you. In my experience, thread schedulers can do a good job at picking unused cores. This means that if you start a new thread on such a machine and do a
Thread.sleep(500)it is very likely that no other process or thread is using the same core as your thread and thus your thread will wake up after that 500ms; most of the time.
To get this to work in even 50% of the cases, the OS must be minimal; any sort of deamon that is running in the background can totally ruin your precision. This means that the serviesservices running on that machine to help you fulfill the event action is also extremely limited. Also, you can only have as many events waiting to trigger at the same time as there are CPU cores in the machine that are guaranteed not to be used.
However you decide to trigger the events, the amount hardware resources is proportiopnalproportional to the the number of events that you can have sitting and waiting to trigger at the same time.
So you'll need to schedule your event triggers carefully in order not to waste expensive resources. Here, the delay of determining the events to trigger comes into play. Lets assume you know about an event that is to be triggered at least 5 seconds beforehand. Within that time, you'll need to get the exact timestamp of the event across to the machine that will trigger + execute. Again, iI see two solutions here:
Database polling might work out but i'dI'd rather use a message queue. I'll not explain why database polling is a bad idea here. A message queue will serve you just as well. Again, you can set up a dedicated service for those events. It knows all events and sends them out to the triggering machines with an accuracy of maybe 3-5 seconds; the triggering machines then handle the millisecond accuracy.
The bottom line is: there might be a couple of more gotchas that i didntI didn't mention (because i dontI don't know them, either). In your place, i'dI'd talk to whoever is the "product owner" of the software and see whether 10ms or 100ms accuracy will also do: