Skip to content

Proposal: PSGI environment cleanup handlers

avar edited this page Sep 10, 2012 · 12 revisions

Summary: Allow middleware and framework authors to register cleanup handlers that get called back once a request is complete.

Background

In CGI and mod_perl, there's been a traditional technique where a main program flushes the output and finishes rendering the page on the web browsers, and then run the tasks that could take a long time. It is often called "poor man's background job processing" because it allows you to run a task without making clients wait for the job to be complete.

CGI example:

print "Content-Type: text/plain\n\n";
print "Hello";
  
close STDOUT;  # this ensures flushing the whole page

long_running_task();

mod_perl example:

$r->pool->cleanup_register(\&long_running_task);

These handlers can also be used to free some resources such as temporary files, or resetting random seeds.

There have been some attempts to achieve the same goal, such as Plack::Middleware::Cleanup and run_after_request patch but there are several issues to this approach:

  • Both of them rely on the lifetime of $env which is not specified in the PSGI specification
  • It doesn't work as expected in CGI and mod_perl environment since the callback handlers get called before a request is complete. (i.e. it will most likely block browsers)
  • The callback handlers can't safely use $env since that will introduce circular reference. You could use weak reference to avoid that.
  • Web application frameworks need to depend on such middleware (like Middleware::Cleanup) to implement the cleanup handler, which may not be desired. That was the reason for the patch to add it as a utility function inside Plack::Util, but that still lets app developers depend on Plack anyway.

Proposal

Introduce a new PSGI environment variables psgix.cleanup and psgix.cleanup.handlers, to probe the capabilities of running cleanup handlers and also let applications/middleware to register callbacks to be called once a request is complete. They will be specified as follows:

  • psgix.cleanup - A boolean flag whether a PSGI server supports cleanup handlers. Absence of the key assumes false (i.e. unsupported). Middleware and applications MUST check this key before utilizing the cleanup handlers.
  • psgix.cleanup.handlers - Array reference to stack callback handlers. This reference SHOULD be initialized as an empty array reference by the servers. Applications can register the callbacks by simply push()ing a code reference to this array reference. Callbacks will be called once a request is complete, and it will receive $env as its first argument, and return value of the callbacks will be simply ignored. An exception thrown inside callbacks MAY also be ignored.

For most servers the implementation is straightforward, calling the callbacks once a request is complete. For CGI handler we can close STDOUT before doing so, and mod_perl handlers can use PerlCleanupHandlers mechanism.

If the server also supports psgix.harakiri, it SHOULD implement in a way that cleanup handlers run before harakiri checker, so that the cleanup handlers can commit the harakiri flag.

Considerations

  • The functionalities of cleanup handlers and streaming handlers are very similar, while the intent of them can be made very clear.
  • cleanup handlers may not have access to all elements in the PSGI env, such as psgi.input.
  • Middleware for exception handling or logging handlers probably doesn't work inside cleanup handlers.

Comments to https://github.com/plack/psgi-specs/issues/18

Status

2011.09.06 Proposed

Implementations

See Also