Тимчасові опції (Transients API)

У WordPress є механізм тимчасового кешування – так зване Транзитне кешування . При такому кешуванні дані зберігаються в базі даних WordPress, в таблицюwp_options на вказаний проміжок часу.

Даний тип кешування підходить для збереження результату складних чи довгих операцій. Наприклад, збереження результату HTTP запиту або збереження результату важкого SQL запиту.

Тимчасові опції (Транзитні опції, Transients) стандартизують кешування даних до бази даних (або об’єктний кеш). Дані зберігаються як пари ключ = значениекотрим вказується час життя. після закінчення часу життя дані будуть видалені або перезаписані (буде видалено рядок у БД).

Тимчасові опції ідентичні звичайним опціям WordPress. Відрізняються лише тим, що до тимчасових опцій додається час опції.

ВАЖЛИВО! Якщо у вас кешем об’єктів , тобто. дані у разі зберігаються туди, а чи не в Базу даних.

Авто-завантаження опцій

Як ви знаєте, всі опції з прапором autoloadу таблиці wp_optionsзапитуються одним запитом і зберігаються в об’єктний кеш. параметр $autoload в add_option() .

Однак, якщо для тимчасової опції встановлено час життя – параметр $expiration , то така опція не завантажуватиметься автоматично в об’єктний кеш, а при її отриманні буде робитися два простих запити до БД: один на отримання самої опції, інший на отримання часу життя опції.

Усі Функції транзитних опцій

get_transient( $transient )
Отримує значення часової опції.
set_transient( $transient, $value, $expiration )
Встановлює або оновлює часову опцію.
get_site_transient( $transient )
Отримує значення тимчасової опції головного веб-сайту мережі.
set_site_transient( $transient, $value, $expiration )
Встановлює або оновлює тимчасові дані для сайту в мультисайті.
delete_expired_transients( $force_db )
Видаляє всі прострочені часові налаштування (транзитні налаштування).
delete_site_transient( $transient )
Deletes a site transient.
delete_transient( $transient )
Видаляє тимчасову опцію.

Використання транзитних опцій

Найпростіший приклад

Допустимо нам потрібно отримати HTML з віддаленого сайту та вивести його на своєму сайті. Нехай це буде блоком останніх новин.

$key = 'last_news_fetch';

$html = get_transient($key);

if ( $html === false ) {

	// отримуємо HTML
	$resp = wp_remote_get( 'https://example.com/api/last-news' );
	$html = wp_remote_retrieve_body( $resp );

	set_transient($key, $html, HOUR_IN_SECONDS);
}

echo $html;

Готво, тепер запит буде робити лише раз на годину.

Тут важливо очистити отриманий HTML код для безпеки, але цей момент я пропустив у коді для простоти сприйняття. Для очищення можна використовувати wp_kses() .

Отримаємо лайки з API Facebook

Припустимо, у нас є функція, яка звертається до API Facebook, запитує об’єкт (точніше сторінку) wpmag.ru і повертає кількість лайків цієї сторінки.

function get_facebook_followers_count() {

	$result = wp_remote_get( 'https://graph.facebook.com/wpmag.ru');
	$result = wp_remote_retrieve_body($result);
	$result = json_decode($result);

	return $result->likes;
}

echo "Кількість лайків: ". get_facebook_followers_count();

Час виконання цієї функції величезний і може тривати 0.5-2 секунди. Це означає, що при використанні цієї функції на сайті час завантаження кожної сторінки зросте на цей час.

Щоб прискорити цю функцію, можна скористатися транзитним кешуванням WordPress і зберегти результат на 1 годину:

function get_facebook_followers_count() {

	$cache_key = 'fb_followers';

	// Видача з транзитного кешу
	$ cached = get_transient ($ cache_key);

	if ( $cached !== false ) {
		return $cached;
	}

	$result = wp_remote_get( 'https://graph.facebook.com/wpmag.ru');
	$result = wp_remote_retrieve_body($result);
	$result = json_decode($result);
	$likes = $result->likes;

	// Запис до транзитного кешу на 1 годину
	set_transient ($ cache_key, $likes, HOUR_IN_SECONDS);

	return $likes;
}

Таким чином, при викликі цієї функції перший раз, після отримання запиту від Facebook, WordPress запише результат у базу даних і надалі протягом години видаватиме цей результат з бази даних, не роблячи повторних запитів на сервер Facebook. А за годину, функція знову звернутися до Facebook за даними.

За допомогою такого підходу лише один дзвінок цієї функції в годину збільшить час запиту на 1-3 секунди, а наступні дзвінки будуть видаватися миттєво.

Але для високонавантажених проектів, на жаль, навіть такий варіант не підходить. Докладніше читайте нижче .

Серіалізація значень

Якщо значення потрібно серіалізувати, робити це окремо не обов’язково, WP робить це автоматично перед збереженням.

Спеціальні константи часу

У WordPress є спеціальні константи часу, створені для зручності:

MINUTE_IN_SECONDS // 60 (секунд)
HOUR_IN_SECONDS // 60*MINUTE_IN_SECONDS
DAY_IN_SECONDS // 24* HOUR_IN_SECONDS
WEEK_IN_SECONDS // 7*DAY_IN_SECONDS
YEAR_IN_SECONDS // 365 * DAY_IN_SECONDS

Видалення транзитних опцій

Очищення часових опцій

WP видаляє всі прострочені транзитні опції автоматично після закінчення терміну давності. Для цього delete_expired_transients() .

Коли потрібно видалити транзитну опцію вручну можна використовувати функцію delete_transient( $transient ) . Це корисно в тих випадках, коли певна дія (збереження повідомлення, додавання категорії тощо) потребує також оновлення транзитної опції.

Наприклад, нам потрібно видалити тимчасову опцію під назвою special_query_results:

delete_transient( 'special_query_results');

Транзитне кешування у високонавантажених проектах

Проблема з транзитним кешуванням у високовідвідуваних проектах у тому, що при закінченні терміну кешу, з’являється час, протягом якого кожен запит може повторно запустити процедуру оновлення даних з API Facebook.

У прикладі оновлення транзитного кеша займає 1-3 секунди. При навантаженні 50 запитів на секунду ми можемо отримати до 50-150 запитів, які спробують оновити цей же транзитний кеш.

Іншими словами, це 50-150 HTTP запитів на Facebook, і до 150 запитів із затримкою в 1-3 секунди (у кращому випадку). Для проекту такого масштабу це катастрофа.

Такі проблеми часто називають станом гонки або race conditions, і вирішити їх допомагають блокування. Наприклад, перед запитом на Facebook для отримання нових даних наша функція може встановити прапорець, який стане сигналом для інших запитів, що оновлення даних вже в процесі, і повторні запити до Facebook виконувати не варто.

function get_facebook_followers_count() {
	// Видача з транзитного кешу
	$cached = get_transient( 'fb_followers' )
	if ( $cached !== false )
		return $cached;

	// Встановити блокування
	$lock = my_acquire_lock( 'fb_followers');
	if (! $lock)
		return 0;

	$result = wp_remote_get( 'https://graph.facebook.com/wpmag.ru');
	$result = json_decode(wp_remote_retrieve_body($result));
	$likes = $result->likes;

	// Запис до транзитного кешу на 1 годину
	set_transient( 'fb_followers', $likes, 1 * HOUR_IN_SECONDS );

	// Зняти блокування
	my_release_lock('fb_followers');

	return $likes;
}

Функції my_acquire_lock()є my_release_lock()псевдо-функціями, вони тут лише для демонстрації. Механізм для блокувань може бути різним залежно від проекту, наприклад, сервер Memcachedабо Redis, GET_LOCK() у MySQL, або навіть додатковий транзит у WordPress.

Таким чином, перший запит на оновлення транзитного кешу встановить іменне блокування. Наступні запити спробують встановити блокування але зможуть, т.к. вона вже присвоєна першому запиту, тому наступні запити повертатимуть 0 доки не закінчиться оновлення транзитного кешу.

Цей метод є далеко не ідеальним з двох основних причин:

  • Деякі відвідувачі зможуть побачити неточну кількість лайків протягом 1-3 секунд
  • Перший запит додасть 1-3 секунди до часу завантаження сторінки

Можна звичайно піти далі, записати останню кількість лайків в опцію і повертати її замість нуля, а оновлення опції можна зробити фоновим за допомогою планувальника завдань в WordPress. Але місцем цього можна використовувати бібліотеку TLC Transients.

Бібліотека TLC Transients

TLC Transients – це бібліотека, написана Марком Джейквітом, одним із провідних розробників ядра WordPress. Вона забезпечує функціонал схожий із звичайним транзитним кешем у WordPress, але має деякі приємні доповнення:

  • При закінченні терміну кешу значення не видаляється
  • Оновлення кешу відбувається виключно за допомогою фонового запиту
  • Зручний синтаксис для отримання та оновлення кешу

Розглянемо приклад використання бібліотеки TLC Transients на основі нашого завдання отримати кількість лайків сторінки Facebook:

// Отримати кількість лайків сторінки у Facebook
function get_facebook_followers_count() {
	$result = wp_remote_get( 'https://graph.facebook.com/wpmag.ru');
	$result = json_decode(wp_remote_retrieve_body($result));
	return $result->likes;
}

// Вивести кількість лайків за допомогою TLC Transients
echo tlc_transient( 'fb_followers' )
	->updates_with( 'get_facebook_followers_count' )
	->expires_in( 1 * HOUR_IN_SECONDS )
	->background_only()
	-> get ();

Функція get_facebook_followers_count()звертається до Facebook API за даними, але, на відміну від нашого першого прикладу, цю функцію ми ніколи не викликаємо безпосередньо. Натомість ми використовуємо об’єкт, tlc_transient()вказавши нашу функцію для оновлення, час життя кешу та примусовий фоновий режим.

Якщо транзитний об’єкт fb_followersіснує, то він буде виведений на екран. Якщо ж час його життя минув, він все одно буде виведений на екран, але при цьому у фоновому режимі окремим запитом запуститься процедура оновлення даних, причому лише один раз.

Врахуйте, що функція, що передається методу, updates_with()повинна існувати в основному контексті WordPress, оскільки процедура оновлення виконується асинхронно окремо від поточного запиту.

Докладніше про проект TLC Transients можна дізнатися на GitHub , де ви знайдете вихідний код бібліотеки та кілька додаткових прикладів.

Джерело

Використовував при написанні:

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *