I created module to import users from other DB to drupal. I used batch API, tried all kind of combinations but It is usually very slow in doing this and also constantly breaking with error
General error: 1205 Lock wait timeout exceeded; try restarting transaction: INSERT INTO {users}...
I also tried changing "batch config" with raising
if ($batch['progressive'] && timer_read('batch_processing') > 10000)
to 10 seconds or so (found this advice somewhere) but it didnt help. What I realised is the user_save(null, $newUser) makes this happen. For some reason saving new users data makes this problem, when I remove it batch goes without the problem to the end.
Here is the full module code, with comments and lots of testing code and different variables that can be set, but whatever I changed the same situation happens.
<?php
/**
* Implementation of hook_menu()
*/
function import_user_migration_menu() {
$items['admin/config/import_user_migration_form'] = array(
'title' => t('Migrate users from old site.'),
'page callback' => 'drupal_get_form',
'page arguments' => array('import_user_migration_form'),
'access arguments' => array('administer site configuration'),
);
return $items;
}
function import_user_migration_form($form, &$form_state) {
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Start processing...'),
);
return $form;
}
function import_user_migration_form_submit($form, &$form_state) {
//switch to old user db
_import_user_migration_switch_to_old();
$start = 0;
$end_count = 50;
$query = db_select('lelo_customer_temp', 't');
$query->fields('t', array('customerId', 'email_address', 'password', 'cust_name'));
$query->condition('t.password', '', '<>');
$query->range($start, $end_count);
//$query->condition('t.Cust_Bill_Email', '', '<>');
$results = $query->execute()->fetchCol();
$user_count = count($results);
//$user_count = 450;
$batch_size = 50;
//Break up all of our data so each process does not time out.
$chunks = array_chunk($results, $batch_size);
$operations = array();
$count_chunks = count($chunks);
//switch to new db
db_set_active('default');
//for every chunk, assign some method to run on that chunk of data
$i = 0;
foreach ($chunks as $chunk) {
$i++;
$operations[] = array("import_user_migration_batch_process", array( $chunk ,'details'=> t('(Importing chunk @chunk of @count)', array('@chunk '=>$i, '@count'=>$count_chunks)), $batch_size));
}
$batch = array(
'operations' => $operations,
'init_message' => t('Batch is starting.'),
'progress_message' => t('Processed @current out of @total.'),
'error_message' => t('Batch has encountered an error.'),
'finished' => 'import_user_migration_batch_finished',
);
batch_set($batch);
}
function import_user_migration_batch_process($uids, $operation_details, $batch_size, &$context) {
//set defaults for the first time
if (!isset($context['sandbox']['progress'])) {
$context['sandbox']['progress'] = 0;
$context['sandbox']['current_user'] = 0;
$context['sandbox']['max'] = $batch_size ;
}
$context['message'] = $operation_details; //Will show what chunk we're on.
//dpm($context);
foreach ($uids as $uid) {
_import_user_migration_switch_to_old();
$old_user = _import_user_migration_user_load($uid);
db_set_active('default');
$user_info = array(
'uid' => $uid,
'name' => $old_user['cust_name'],
'pass' => $old_user['password'],
'mail' => check_plain($old_user['email_address']),
);
// Update our progress information.
$context['sandbox']['progress']++;
$context['sandbox']['current_user'] = $uid;
$context['message'] = "Working on " . $old_user['cust_name'] . ' : ' . check_plain( $old_user['email_address']);
$context['results'][] = $old_user['cust_name'] . ' : ' . check_plain( $old_user['email_address']);
//Notice: Trying to get property of non-object in import_user_migration_batch_process() (line 94 of /Applications/MAMP/htdocs/lelo-pht/sites/all/modules/custom/import_user_migration/import_user_migration.module).
if (user_load_by_mail(check_plain($old_user['email_address']))) {
//user found
} else {
//user NOT found
_import_user_migration_create_user($user_info);
}
}
// Inform the batch engine that we are not finished,
// and provide an estimation of the completion level we reached.
if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
$context['finished'] = ($context['sandbox']['progress'] >= $context['sandbox']['max']);
}
_import_user_migration_update_http_requests();
}
function import_user_migration_batch_finished($success, $results, $operations) {
if ($success) {
// Here we could do something meaningful with the results.
// We just display the number of nodes we processed...
drupal_set_message(t('@count results processed in @requests HTTP requests.', array('@count' => count($results), '@requests' => _import_user_migration_get_http_requests())));
drupal_set_message(t('The final result was "%final"', array('%final' => end($results))));
}
else {
// An error occurred.
// $operations contains the operations that remained unprocessed.
$error_operation = reset($operations);
drupal_set_message(t('An error occurred while processing @operation with arguments : @args', array(
'@operation' => $error_operation[0],
'@args' => print_r($error_operation[0], TRUE),
)));
}
}
/**
* Switch to database import_user
*/
function _import_user_migration_switch_to_old() {
$other_database = array(
'database' => 'users',
'username' => 'root',
'password' => 'root',
'host' => 'localhost',
'driver' => 'mysql',
);
Database::addConnectionInfo('old', 'default', $other_database);
db_set_active('old');
}
/**
* Create a user in new site
*
* @param array $user_info
* array('uid', 'name', 'pass', 'mail')
*/
function _import_user_migration_create_user($user_info) {
$newUser = array(
'name' => $user_info['name'],
'pass' => $user_info['pass'],
'mail' => $user_info['mail'],
'status' => 1,
'init' => $user_info['mail'],
'roles' => array(DRUPAL_AUTHENTICATED_RID => 'authenticated user'),
);
user_save(null, $newUser);
}
/**
* Load old user data
*
* @return array
* array('uid', 'name', 'pass', 'mail')
*/
function _import_user_migration_user_load($uid) {
$query = db_select('lelo_customer_temp', 't');
$query->fields('t', array('customerId', 'cust_name', 'password', 'email_address'));
$query->condition('t.customerId', $uid);
$results = $query->execute()->fetchObject();
return (array) $results;
}
function _import_user_migration_update_http_requests() {
$_SESSION['http_request_count']++;
}
function _import_user_migration_get_http_requests() {
return !empty($_SESSION['http_request_count']) ? $_SESSION['http_request_count'] : 0;
}