diff --git a/agrcache.module b/agrcache.module
index 7133c23..4111801 100644
--- a/agrcache.module
+++ b/agrcache.module
@@ -411,13 +437,7 @@ function agrcache_generate_aggregate($filename, $type) {
     $data = $function($map['callbacks'][$uri]);
     // Check file_exists() again, in case the file was built during processing.
     if (!file_exists($uri)) {
-      // Create the file.
-      file_prepare_directory($path, FILE_CREATE_DIRECTORY);
-      if (!file_exists($uri) && !file_unmanaged_save_data($data, $uri, FILE_EXISTS_REPLACE)) {
-        drupal_add_http_header('Status', '503 Service Unavailable');
-        print t('Error generating aggregate');
-        drupal_exit();
-      }
+      _agrcache_file_unmanaged_save_data($data, $path, $uri);
       // If gzip compression is enabled, clean URLs are enabled (which means
       // that rewrite rules are working) and the zlib extension is available then
       // create a gzipped version of this file. This file is served conditionally
@@ -425,7 +445,7 @@ function agrcache_generate_aggregate($filename, $type) {
       if ($compression) {
         $compressed = gzencode($data, 9, FORCE_GZIP);
         if (!file_exists($uri . '.gz')) {
-          file_unmanaged_save_data($compressed, $uri . '.gz', FILE_EXISTS_REPLACE);
+          _agrcache_file_unmanaged_save_data($data, $path, $uri . '.gz');
         }
       }
     }
@@ -448,6 +468,29 @@ function agrcache_generate_aggregate($filename, $type) {
 }
 
 /**
+ * Helper to atomically write a file.
+ */
+function _agrcache_file_unmanaged_save_data($data, $path, $uri) {
+  // Create the file.
+  file_prepare_directory($path, FILE_CREATE_DIRECTORY);
+  $tmp_uri = $uri . drupal_random_bytes(10);
+  // file_unmanaged_save_data() uses copy, which is not atomic and could
+  // result in empty files being served from other requests while the file
+  // is being written. So write it to a temporary filename, then use
+  // rename() afterwards, which is atomic.
+  $write = file_unmanaged_save_data($data, $tmp_uri, FILE_EXISTS_REPLACE);
+  if ($write) {
+    // It's possible another process has already written the aggregate and
+    // renamed it, so suppress errors.
+    @rename($tmp_uri, $uri);
+  }
+  else {
+    trigger_error('Agrcache failed to write aggregate . ' . $uri . ' successfully.');
+  }
+  return $write;
+}
+
+/**
  * Merge the existing file list with new values.
  *
  * @param $type
