Выполнение необходимых действий на сервере в несколько подходов

2012-10-15 11:00:00


Уважаемые читатели, в этой статье я расскажу как осуществить выполнение ресурсоёмких задач на сервере, разбив их выполнение на несколько этапов. Но сначало немного предыстории. Передо мной встала задача обработки файлов с изображениями, а именно нужно было сгенерировать маленькие иконки из полноразмерных высококачественных фотографий, объем которых составлял более мегабайта.

Загрузив около 300 таких фотографий на сервер, я запустил скрипт генерациии иконок. После 30 секунд ожидания результат от скипта, сервер выдал ошибку времени выполнения скрипта. В настройках сервера это время было ограничено 30-ю секундами.

Можно конечно в php коде его увеличить, добавив строчку:

set_time_limit(n); // где n - количество секунд.

Но это плохое решение, ведь фотографий может быть во много раз больше. Поразмыслив, я решил разбить задачу на несколько этапов. А именно за один запуск скрипта обрабатывать не более 10 фотографий. Я реализовал данную задачу я с помощью технологии Ajax.

Чтобы не грузить вас лишним кодом, а просто продемонстрировать свой подход, я сделал небольшой примерчик: есть скрипт php счётчика. При каждом обращении к скрипту, значение счётчика увеличивается на единицу. Значение хранится в txt файле. Запускать скрипт будется из html странички.

Описание файлов скрипта:

index.html - страница, в которой мы будем задавать желаемую сумма для счётчика и запускать php скрипт action.js - JavaScript код. Для упрощения работы с js используется библиотека Jquery counter.php - скрипт нашего счётчика data.txt - в этом файле хранится значение счётчика style.css - стили для элементов нашей html странички

.htaccess - файл конфигурации веб-сервера

Рассмотрим в подробнастях содержание каждого файла. Начнём с index.html:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript" src="action.js"></script>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>

<label>Досчитать до: </label>
<input type="text" value="5" id="maximum" />
<input type="button" value="Запустить счётчик" id="start" />

<div id="status">
	<div id="process"></div>
</div>

</body> 
</html>

В блоке head подключается библиотека jquery, которая упростит нашу работу с JavaScript и Ajax. Подключаем файл скрипта action.js и файл стилей style.css Сама html страница содержит в себе поле input, в котором вводится значение для счётчика, и кнопка запустить счётчик.

Алгоритм работы следующий: пользователь вводит число, до которого скрипт будет считать и нажимает кнопку. При клике на кнопку запускается фуннкция, которая и запускает counter.php до тех пор, пока значение счётчика не достигнет заданного числа.

Теперь рассмотрим содержимое action.js:


$(function() {
	var maximum = 0;
	var counter = 1;
	$('#start').click(
		function() {
			counter = 1;
			maximum = $('#maximum').val();
			maximum = parseInt(maximum);
			$('#process').empty(); // Чистим блок с логами
			$('#start').attr('disabled','disabled'); // Делаем кнопку неактивной
			startPhpScript();
	});

	function startPhpScript(){
		$.ajax({
			type: 'GET',
			url:  'counter.php',
			success: function(result){
				if (parseInt(result) < maximum){
					startPhpScript(); // Рекурсия
					$('#process').append('Скрипт запущен ' + counter + ' раз<br />');
					counter++;
				} else {
					$('#process').append('Скрипт запущен ' + counter + ' раз<br />' + 'Действие выполнено в ' + counter + ' этапов');
					$('input').removeAttr('disabled'); //Делаем кнопку активной
				}

			}
		});
		
	}
});

При нажатии кнопки запускается функция startPhpScript(), в которой средствами ajax посылается асинхронный запрос к скрипту counter.php. Текущее значение счётчика, полученная со стороны сервера сравнивается с заданным нами числом. Если значение счетчика меньше нашего числа, используем рекурсию (вызов функции из неё же самой). И так до тех пор, пока значение счётчика не будет удовлетворять нашим условьям.

А вот и сам счётчик counter.php:


<?php
	if (file_exists('data.txt')){
		$fp  =fopen('data.txt', 'a+');
		$num = intval(fgets($fp, 999));
		$num++;
		ftruncate($fp,0);
		fputs($fp, $num); 
		fclose($fp);
		echo $num;
	}
?>

Здесь всё просто. Считываем значение счётчика из файла. Увеличиваем значение на единичку. Затираем содержимое файла и записываем результат нашей суммы, который еще и выводим на экран (его то и получает наша функция-обработчик).

Я показал вам на простом примере как реализовать данный подход. В реальной практике возможно вам придётся разработать менеджер задач, который будет сохранять положения, в которых текущий запуск скрипта закончил работу, для того чтобы при следующем запуске обработка данных начиналось с нужного места.

Если будут какие-либо вопросы, отзывы, предложения - пишите в комментариях.