diff --git a/agrcache.module b/agrcache.module
index 7133c23..348e623 100644
--- a/agrcache.module
+++ b/agrcache.module
@@ -31,6 +31,10 @@ function agrcache_element_info_alter(&$type) {
   if (isset($type['styles']['#aggregate_callback'])) {
     $type['styles']['#aggregate_callback'] = 'agrcache_aggregate_css';
   }
+  if (isset($type['styles']['#pre_render'])) {
+    // Add our pre_render callback.
+    $type['styles']['#pre_render'][] = 'agrcache_pre_render_styles';
+  }
 }
 
 /**
@@ -214,9 +218,11 @@ function agrcache_get_js($scope = 'header', $javascript = NULL, $skip_alter = FA
       // Only include the file if was written successfully. Errors are logged
       // using watchdog.
       if ($uri) {
-        $preprocess_file = file_create_url($uri);
+        // Append the css/js query string to force browser and edge caches
+        // to update even if the filename itself has not changed.
+        $preprocess_url = file_create_url($uri) . "?=$query_string";
         $js_element = $element;
-        $js_element['#attributes']['src'] = $preprocess_file;
+        $js_element['#attributes']['src'] = $preprocess_url;
         $processed[$key] = theme('html_tag', array('element' => $js_element));
       }
     }
@@ -270,6 +276,24 @@ function agrcache_aggregate_css(&$css_groups) {
 }
 
 /**
+ * Pre-render callback for styles.
+ */
+function agrcache_pre_render_styles($elements) {
+  $query_string = variable_get('css_js_query_string', 0);
+  foreach ($elements['#groups'] as $delta => $group) {
+    if ($elements['#groups'][$delta]['type'] == 'file') {
+      $elements['#groups'][$delta]['data'] = $elements['#groups'][$delta]['data'] . "?=$query_string";
+    }
+  }
+  foreach (element_children($elements) as $key) {
+    if (isset($elements[$key]['#attributes']['href'])) {
+      $elements[$key]['#attributes']['href'] = $elements[$key]['#attributes']['href'] . "?=$query_string";
+    }
+  }
+  return $elements;
+}
+
+/**
  * Replacement for drupal_build_css_cache() and drupal_build_js_cache().
  */
 function agrcache_build_aggregate_cache($files, $type) {
@@ -400,24 +424,41 @@ function agrcache_generate_aggregate($filename, $type) {
   // However it is possible that the file was created during bootstrap by another request.
   if (file_exists($uri)) {
     $data = file_get_contents($uri);
-    if ($compression) {
-      $compressed = gzencode($data, 9, FORCE_GZIP);
-    }
   }
   elseif (isset($map['callbacks'][$uri])) {
+    // There is a possible race condition in the following deployment case with
+    // multiple web heads.
+    //   - server A has updated code, and gets a page request - i.e. builds a
+    //     filename.
+    //   - server B (this server) is not updated yet, and gets a request for an
+    //   aggregate with that filename.
+    // In this case, server 2 cannot assume that the filename matches the
+    // actual contents of the files on disk, since the files on disk are in
+    // fact different, given the filename was generated on a different server,
+    // with different files. Based on the information in the map, build the
+    // filename again, and ensure they match. Since the filename depends on
+    // the contents of the files, if the filenames don't match we know we've
+    // hit this race condition. When that happens, log an error, don't write
+    // the aggregate, but still serve the contents of the old file, which is
+    // the best we can do.
+    $write = TRUE;
+    $function = 'agrcache_collect_' . $type . '_group';
+    $files = $map['callbacks'][$uri];
+    $this_data = $function($files);
+    $this_filename = $type . '_' . drupal_hash_base64(serialize($files) . $this_data) . ".$type";
+    $path = "public://$type";
+    $this_uri = $path . '/' . $this_filename;
+    if ($this_uri !== $uri) {
+      watchdog('agrcache', 'Attempted to create an aggregate based on a set of files that does not match the filename provided.');
+      $write = FALSE;
+    }
     // @todo: consider adding locking here.
     // @see drupal.org/node/886488
     $function = 'agrcache_process_' . $type . '_group';
     $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();
-      }
+    if (!file_exists($uri) && $write) {
+      _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,26 +466,51 @@ 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($compressed, $path, $uri . '.gz');
         }
       }
     }
-    $content_type = $type == 'css' ? 'text/css' : 'application/javascript';
-    $headers = array();
-    $headers['Content-Type'] = $content_type;
-    // Ensure that only the request that is hitting PHP sees this file,
-    // otherwise we want to use the file on disk for consistency.
-    $headers['Cache-Control'] = 'private, no-cache, no-store';
-    $headers['Edge-Control'] = 'private, no-cache, no-store';
-    foreach ($headers as $key => $value) {
-      drupal_add_http_header($key, $value);
-    }
-    print $data;
-    drupal_exit();
   }
   else {
+    $data = '';
     watchdog('agrcache', 'Received request for a non-existent css aggregate @uri', array('@uri' => $uri));
   }
+
+  $content_type = $type == 'css' ? 'text/css' : 'application/javascript';
+  $headers = array();
+  $headers['Content-Type'] = $content_type;
+  // Ensure that only the request that is hitting PHP sees this file,
+  // otherwise we want to use the file on disk for consistency.
+  $headers['Cache-Control'] = 'private, no-cache, no-store';
+  $headers['Edge-Control'] = 'private, no-cache, no-store';
+  foreach ($headers as $key => $value) {
+    drupal_add_http_header($key, $value);
+  }
+  print $data;
+  drupal_exit();
+}
+
+/**
+ * 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.', E_USER_WARNING);
+  }
+  return $write;
 }
 
 /**
@@ -502,11 +568,20 @@ function agrcache_flush_caches() {
   // @todo: Require PHP 5.3.6 so this can use DEBUG_BACKTRACE_IGNORE_ARGS.
   $backtrace = debug_backtrace(FALSE);
   if (isset($backtrace[3]) && $backtrace[3]['function'] == 'drupal_flush_all_caches') {
-    $values = array(':file_list' => serialize(array('files' => array(), 'callbacks' => array())));
-    db_query("UPDATE {agrcache_files} SET file_list = :file_list", $values);
-    foreach (array('js', 'css') as $type) {
-      cache_clear_all("agrcache_file_list_$type", "cache");
-    }
+    _agrcache_clear_file_list();
+  }
+}
+
+/**
+ * Clear the file list.
+ */
+function _agrcache_clear_file_list() {
+  $file_list = array('files' => array(), 'callbacks' => array());
+  db_update('agrcache_files')
+    ->fields(array('file_list' => serialize($file_list)))
+    ->execute();
+  foreach (array('js', 'css') as $type) {
+    cache_clear_all("agrcache_file_list_$type", "cache");
   }
 }
 
