Last modified: 2012-05-10 19:37:47 UTC
This rarely happens in production, but if a module is loaded that doesn't exist (or can't be returned through load.php because it's private), then the server will (or should) respond with a mw.loader.setState() call. It currently does this in 2 scenarios: * When using only=scripts (usually setting 'ready') * When the module doesn't exist (setting state missing') The former has a work around currently, but the latter is a problem. getState only sets the state in the registry, doesn't cause pending callbacks to be handled. When outright requesting a random inexisting module, all will be fine because the client loader has a registry and won't try to request it if it doesn't exist. But if a module existed at time the startup module was cached but not at time of calling, then the server will (because ResourceLoader does account for this case) respond with setState(.., 'missing'). This case is accounted for because it is very easy to trigger during a deployment: * startup module is generated and cached, with the 2x 5 minute overlap this could be about a 10 minutes overlap * Aside from the possibility for module changes between generation of startup module and client visiting another page, there's also a natural time lapse when modules are loaded on demand. A user can visit a page, read it and have it open for an hour (or longer) and then click something that lazy-loads a module. That module can potentially no longer exist (we've seen this during the 1.19 deployment where jquery.mwPrototypes was renamed to jquery.mwExtension). This bug is a reminder to Roan and I, we originally came across while doing a very in-depth evaluation over the client loader code. Forgot to file earlier. We should try to get this into 1.19.0
Actually, I think the mw.loader state machine is missing several transitions: Currently, handlePending() only executes modules and jobs if all their dependencies are "ready". If any dependency is in any other state, including state "error" or "missing", nothing happens. Furthermore, I think mw.loader.using ahould throw an error if any dependency given is in state "error" or "missing". mw.loader.load should probably not only filter out undefined modules, but also any module where either the module itself or a (direct or indirect) dependency is in state "error" or "missing". Also, I wonder if modules and jobs could not be unified, insofar as a module might register a job that would then run execute(). That would allow handlePending() to care only about jobs. mw.loader.state needs to invoke handlePending() for any state change to a state after "loaded" (i.e., to ready, error, or missing). handlePending() itself should probably also check for jobs (and modules, currently) where any dependency is in state "error" or "missing", and treat the job/module as failed then. Note that this would mean that error stati would propagate up the dependency tree, which they currently don't. This means that modules depending (directly or indirectly) on failed modules will now also be considered to be in state "error". Currently, they just remain in limbo ("loaded") forever; they'll never progress to one of the final states (ready, error, or missing). If we can agree on what exactly should be done, I could tackle this. Would nicely complement bug 32537.
I've implemented a first stab at this in https://gerrit.wikimedia.org/r/#change,6205