I am currently doing this. I have a client running as a Windows Service. At startup service will post a serviceID to the webserver for identification. Its basically just a GUID generated at startup if no existing ID was found.
After enrollment the service will then start a long polling http request at a longpolling web server resource. Web service will park the caller for at set amount of time. If no wakeup calls are received from other services the client request is then answered with a reason. Client will then immediately start a new long polling request after processing the response.
Web service also has a WakeUp resource used for other services to signal that a specific serviceID should receive an actual WakeUp. Longpolling and WakeUp functions share a list of serviceIDs to wake up. Depending on your goals you can have multiple wakup reasons depending on the complexity of your solution.
Windows Service is implemented as a multithreaded application. One general controlling thread that handles general Windows Service management stuff and signals worker threads if service receives OnStop events from the Service Control Manager. Its also the thread that sets every other thing up. Instantiates the other worker threads and starts them.
LongPolling thread which only job is to handle the result of the longpolling call. When a response is received it inspects the result and activates other threads based on the result and then starts a new longpolling request. This means it is able to receive new tasks while the other worker threads are processing their tasks.
And as said you can have multiple different worker threads that do different things. Moves files around, installs applications, deletes ilegal applications, makes backups of folders. The sky really is the limit.
This is pretty much the basic design of my system and it works pretty great. Its simple and easy to use.