Skip to content

Instantly share code, notes, and snippets.

@senior
Created July 15, 2015 14:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save senior/1cbcdf08683eae26b4ae to your computer and use it in GitHub Desktop.
Save senior/1cbcdf08683eae26b4ae to your computer and use it in GitHub Desktop.
Reject requests until started

I’ve done some research and I think I have a solution for this. We’ll create a new bootstrap kind of service that the PuppetDB service will depend on. It will have a function that registers a module’s influence on the startup process of PuppetDB. Function herees that are not terrible are left as an exercise to the reader.

(register-startup-notification [this other-service])
(startup-completed [this other-service])

Interested services, such as the PuppetDB service and the sync service will register in the init phase of the TK lifecycle. This bootstrap service will assoc the service id of other-service in an atom in it’s context. Then in the start function of this new bootstrap service, it will add a catch-all handler at “/” that will always return an error response. Not sure if this should be a web page or just an 500 error with some text, but will service all requests and return the error.

Each service that registered itself will then call startup-completed as the last thing the start function does. This new bootstrap service will remove that handler when all of the registered services have called startup-completed.

tk-jetty change

We don’t currently have the ability to remove a jetty handler. I think this will be fairly easy as Jetty supports this and we have similar functions that add handlers using that low level Jetty API. The add-ring-handler function can be found here. That function returns the Jetty ring handler object that we will need to use to remove the ring handler (i.e. this new function will accept that handler as it’s arg). It would be nice if we could pass the route in (i.e. (remove-handler service “/”)) but Jetty doesn’t expose in their APIs without doing some potentially unsafe casting and guessing about what kind of handlers are present.

The bootstrap service can add the ring handler and create a function that closes over the object and uses that function to remove the handler once the last service has completed. Might be easiest to just add a watcher on the atom.

@ajroetker
Copy link

The tk-jetty change mentioned here is one use case for bidi (comidi I guess for Puppetlabs), basically we want to find a handler by it's route, while comidi specializes in.

@ajroetker
Copy link

I'm gonna play Devil's advocate here.

Why not just use trapperkeeper service lifecycles in a clever way?
If we separated the query-fn and command-fn services (the services which offer in-process command and querying) into their own services (call them pdb-in-proc-query and pdb-in-proc-cmd), and had separate pdb-query-handler and pdb-command-handler services which served our ring handlers in the appropriate places, we could have a service in the middle PuppetDBRegister which relies on the in-process services being up (maybe the in-proc services satisfy a startup-complete interface), the handler services would rely on this PuppetDBRegister function being started before they served our handlers. Then in extensions we could have a different implementation of that same service which also relied on the sync service, and the handler functions would be none-the-wiser.

@mullr
Copy link

mullr commented Jul 23, 2015

Talked with AJ about this and arrived at a variation that may be good:

  • Split the existing http/Query service, so there's a regular Query service which exposes query-fn.
  • Make Sync depend on Query
  • Make a new http/PEQuery service which delegates most of its implementation to Query (upon which it depends) and http/Query (which it doesn't depend on, just pulls in code directly).
  • http/PEQuery depends on Sync.
  • Sync has a new function (ready?) which returns true after a single sync has been completed.
  • http/PEQuery has a new middleware which calls (ready?) from Sync. If it returns false, it returns HTTP 403 or whatever.

The nice thing about this is that it lets the initial sync happen in the background; it doesn't block startup it all, and the rest of the system continues to work. (we can even accept new commands)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment