Proper exception handling in ResourceLoader. Catch exceptions and output them in comments. Instead of just surrounding everything in a big try { } block, catch module-level exceptions where possible to allow error-free modules loaded in the same request to still be output normally. Modules that don't get output because of an exception are marked as missing in the client-side loader so other modules depending on them won't get loaded either.
This commit is contained in:
parent
b3496e5fc9
commit
1d0dd870b8
1 changed files with 75 additions and 53 deletions
|
|
@ -66,7 +66,7 @@ class ResourceLoader {
|
|||
), __METHOD__
|
||||
);
|
||||
|
||||
// Set modules' dependecies
|
||||
// Set modules' dependencies
|
||||
$modulesWithDeps = array();
|
||||
foreach ( $res as $row ) {
|
||||
$this->getModule( $row->md_module )->setFileDependencies( $skin,
|
||||
|
|
@ -117,7 +117,7 @@ class ResourceLoader {
|
|||
*
|
||||
* @param $filter String: Name of filter to run
|
||||
* @param $data String: Text to filter, such as JavaScript or CSS text
|
||||
* @return String: Filtered data
|
||||
* @return String: Filtered data, or a comment containing an error message
|
||||
*/
|
||||
protected function filter( $filter, $data ) {
|
||||
wfProfileIn( __METHOD__ );
|
||||
|
|
@ -151,13 +151,13 @@ class ResourceLoader {
|
|||
$result = CSSMin::minify( $data );
|
||||
break;
|
||||
}
|
||||
} catch ( Exception $exception ) {
|
||||
throw new MWException( 'ResourceLoader filter error. ' .
|
||||
'Exception was thrown: ' . $exception->getMessage() );
|
||||
}
|
||||
|
||||
// Save filtered text to Memcached
|
||||
$cache->set( $key, $result );
|
||||
// Save filtered text to Memcached
|
||||
$cache->set( $key, $result );
|
||||
} catch ( Exception $exception ) {
|
||||
// Return exception as a comment
|
||||
$result = "/*\n{$exception->__toString()}\n*/";
|
||||
}
|
||||
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
|
|
@ -294,6 +294,7 @@ class ResourceLoader {
|
|||
ob_start();
|
||||
|
||||
wfProfileIn( __METHOD__ );
|
||||
$response = '';
|
||||
|
||||
// Split requested modules into two groups, modules and missing
|
||||
$modules = array();
|
||||
|
|
@ -320,7 +321,12 @@ class ResourceLoader {
|
|||
}
|
||||
|
||||
// Preload information needed to the mtime calculation below
|
||||
$this->preloadModuleInfo( array_keys( $modules ), $context );
|
||||
try {
|
||||
$this->preloadModuleInfo( array_keys( $modules ), $context );
|
||||
} catch( Exception $e ) {
|
||||
// Add exception to the output as a comment
|
||||
$response .= "/*\n{$e->__toString()}\n*/";
|
||||
}
|
||||
|
||||
wfProfileIn( __METHOD__.'-getModifiedTime' );
|
||||
|
||||
|
|
@ -328,12 +334,17 @@ class ResourceLoader {
|
|||
// the last modified time
|
||||
$mtime = wfTimestamp( TS_UNIX, $wgCacheEpoch );
|
||||
foreach ( $modules as $module ) {
|
||||
// Bypass squid cache if the request includes any private modules
|
||||
if ( $module->getGroup() === 'private' ) {
|
||||
$smaxage = 0;
|
||||
try {
|
||||
// Bypass squid cache if the request includes any private modules
|
||||
if ( $module->getGroup() === 'private' ) {
|
||||
$smaxage = 0;
|
||||
}
|
||||
// Calculate maximum modified time
|
||||
$mtime = max( $mtime, $module->getModifiedTime( $context ) );
|
||||
} catch ( Exception $e ) {
|
||||
// Add exception to the output as a comment
|
||||
$response .= "/*\n{$e->__toString()}\n*/";
|
||||
}
|
||||
// Calculate maximum modified time
|
||||
$mtime = max( $mtime, $module->getModifiedTime( $context ) );
|
||||
}
|
||||
|
||||
wfProfileOut( __METHOD__.'-getModifiedTime' );
|
||||
|
|
@ -379,7 +390,7 @@ class ResourceLoader {
|
|||
}
|
||||
|
||||
// Generate a response
|
||||
$response = $this->makeModuleResponse( $context, $modules, $missing );
|
||||
$response .= $this->makeModuleResponse( $context, $modules, $missing );
|
||||
|
||||
// Capture any PHP warnings from the output buffer and append them to the
|
||||
// response in a comment if we're in debug mode.
|
||||
|
|
@ -405,62 +416,73 @@ class ResourceLoader {
|
|||
public function makeModuleResponse( ResourceLoaderContext $context,
|
||||
array $modules, $missing = array() )
|
||||
{
|
||||
$out = '';
|
||||
if ( $modules === array() && $missing === array() ) {
|
||||
return '/* No modules requested. Max made me put this here */';
|
||||
}
|
||||
|
||||
// Pre-fetch blobs
|
||||
if ( $context->shouldIncludeMessages() ) {
|
||||
$blobs = MessageBlobStore::get( $this, $modules, $context->getLanguage() );
|
||||
//try {
|
||||
$blobs = MessageBlobStore::get( $this, $modules, $context->getLanguage() );
|
||||
//} catch ( Exception $e ) {
|
||||
// Add exception to the output as a comment
|
||||
// $out .= "/*\n{$e->__toString()}\n*/";
|
||||
//}
|
||||
} else {
|
||||
$blobs = array();
|
||||
}
|
||||
|
||||
// Generate output
|
||||
$out = '';
|
||||
foreach ( $modules as $name => $module ) {
|
||||
|
||||
wfProfileIn( __METHOD__ . '-' . $name );
|
||||
try {
|
||||
// Scripts
|
||||
$scripts = '';
|
||||
if ( $context->shouldIncludeScripts() ) {
|
||||
$scripts .= $module->getScript( $context ) . "\n";
|
||||
}
|
||||
|
||||
// Scripts
|
||||
$scripts = '';
|
||||
if ( $context->shouldIncludeScripts() ) {
|
||||
$scripts .= $module->getScript( $context ) . "\n";
|
||||
}
|
||||
// Styles
|
||||
$styles = array();
|
||||
if ( $context->shouldIncludeStyles() ) {
|
||||
$styles = $module->getStyles( $context );
|
||||
}
|
||||
|
||||
// Styles
|
||||
$styles = array();
|
||||
if ( $context->shouldIncludeStyles() ) {
|
||||
$styles = $module->getStyles( $context );
|
||||
}
|
||||
// Messages
|
||||
$messagesBlob = isset( $blobs[$name] ) ? $blobs[$name] : '{}';
|
||||
|
||||
// Messages
|
||||
$messagesBlob = isset( $blobs[$name] ) ? $blobs[$name] : '{}';
|
||||
|
||||
// Append output
|
||||
switch ( $context->getOnly() ) {
|
||||
case 'scripts':
|
||||
$out .= $scripts;
|
||||
break;
|
||||
case 'styles':
|
||||
$out .= self::makeCombinedStyles( $styles );
|
||||
break;
|
||||
case 'messages':
|
||||
$out .= self::makeMessageSetScript( new XmlJsCode( $messagesBlob ) );
|
||||
break;
|
||||
default:
|
||||
// Minify CSS before embedding in mediaWiki.loader.implement call
|
||||
// (unless in debug mode)
|
||||
if ( !$context->getDebug() ) {
|
||||
foreach ( $styles as $media => $style ) {
|
||||
$styles[$media] = $this->filter( 'minify-css', $style );
|
||||
// Append output
|
||||
switch ( $context->getOnly() ) {
|
||||
case 'scripts':
|
||||
$out .= $scripts;
|
||||
break;
|
||||
case 'styles':
|
||||
$out .= self::makeCombinedStyles( $styles );
|
||||
break;
|
||||
case 'messages':
|
||||
$out .= self::makeMessageSetScript( new XmlJsCode( $messagesBlob ) );
|
||||
break;
|
||||
default:
|
||||
// Minify CSS before embedding in mediaWiki.loader.implement call
|
||||
// (unless in debug mode)
|
||||
if ( !$context->getDebug() ) {
|
||||
foreach ( $styles as $media => $style ) {
|
||||
$styles[$media] = $this->filter( 'minify-css', $style );
|
||||
}
|
||||
}
|
||||
}
|
||||
$out .= self::makeLoaderImplementScript( $name, $scripts, $styles,
|
||||
new XmlJsCode( $messagesBlob ) );
|
||||
break;
|
||||
}
|
||||
$out .= self::makeLoaderImplementScript( $name, $scripts, $styles,
|
||||
new XmlJsCode( $messagesBlob ) );
|
||||
break;
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
// Add exception to the output as a comment
|
||||
$out .= "/*\n{$e->__toString()}\n*/";
|
||||
|
||||
// Register module as missing
|
||||
$missing[] = $name;
|
||||
unset( $modules[$name] );
|
||||
}
|
||||
wfProfileOut( __METHOD__ . '-' . $name );
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue