Написание идемпотентного кода: руководство

Написание идемпотентного кода: руководство

29 октября 2023 г.

Введение

При разработке программного обеспечения крайне важно писать надежный код, особенно при работе с распределенными системами и микросервисами. Одним из способов достижения этой надежности является идемпотентность. Но что означает «идемпотент» и как написать идемпотентный код?

Что такое идемпотентность?

Идемпотентность в программировании и математике — это свойство некоторых операций, при котором независимо от того, сколько раз вы их выполняете, вы достигаете одного и того же результата.

Например, нажатие кнопки «стоп» на будильнике является идемпотентным. Независимо от того, нажмете ли вы ее один или пять раз, будильник останется отключенным. С другой стороны, нажатие кнопки «увеличить громкость» не идемпотентно, каждое нажатие увеличивает громкость.

Почему идемпотентность важна?

Идемпотентность необходима по нескольким причинам:

  • Восстановление ошибок: если система выйдет из строя во время операции, вы можете безопасно повторить операцию, не беспокоясь о неблагоприятных последствиях.

* Параллелизм: в распределенной системе несколько узлов могут попытаться выполнить одну и ту же операцию. Идемпотентность гарантирует, что конечный результат останется неизменным.

* Пользовательский опыт: пользователи могут обновить страницу или нажать кнопку несколько раз без непредвиденных побочных эффектов.

Как написать идемпотентный код

Очистите результат перед его обновлением

Перед выполнением операций удаляйте данные из таблиц и переназначайте значения переменным. Если вы хотите добавлять только новые данные, очистите раздел, с которым работаете.

ALTER TABLE table_name DROP IF EXISTS PARTITION(year = 2022, month = 12);

INSERT INTO TABLE table_name PARTITION (year = 2022, month = 12)
SELECT * FROM another_table

WHERE some_condition;

Транзакции с базой данных

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

BEGIN TRANSACTION;

UPDATE accounts SET balance = balance - 1000 WHERE account_id = 1;

UPDATE accounts SET balance = balance + 1000 WHERE account_id = 2;

COMMIT;

Ключи идемпотентности

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

Если это так, сервер возвращает предыдущий ответ вместо повторного выполнения операции.

registrations = {}
def register_user(idempotency_key, user_data):
    if idempotency_key in registrations:
        return registrations[idempotency_key]
    # App logic here
    registrations[idempotency_key] = "User registered"
    return registrations[idempotency_key]

Используйте безопасные методы HTTP для веб-служб

Если вы создаете RESTful API, используйте методы HTTP, которые по своей сути идемпотентны, например GET, PUT, DELETE и HEAD. Избегайте использования POST или используйте ключи идемпотентности, как в примере выше.

Идемпотентность предмета

Для таких операций, как «добавить в корзину», вы можете сделать операцию идемпотентной, указав конечное состояние, а не изменение. Например, вместо «добавить один элемент» можно использовать операцию «установить количество элементов равным 1».

# Server-side Python code
cart = {}

def set_cart_item(item_id, quantity):
    cart[item_id] = quantity

Использовать конечные автоматы

Конечные автоматы также могут быть полезны для обеспечения идемпотентности. Они определяют возможные состояния системы и переходы между ними. Проверив текущее состояние перед выполнением операции, вы можете убедиться в ее идемпотентности.

jobs = {}

def run_job(job_id):
    if jobs[job_id] == "queued":
        jobs[job_id] = "running"
        #Start the job

Проверка на идемпотентность

Проверить идемпотентность несложно. Выполните операцию один раз и запишите результат. Затем выполните операцию несколько раз и сравните результаты. Они должны быть одинаковыми.

def test_idempotence_delete():
    initial_result = update_user(1, {"name": "Yuri", "age": 30})
    repeat_result = update_user(1, {"name": "Yuri", "age": 30})
    assert initial_result == repeat_resultpy

Обратите внимание, что в распределенной системе проверка идемпотентности может быть более сложной из-за таких проблем, как задержка в сети, сбои и т. д.

Заключение

Написание идемпотентного кода — это не просто лучшая практика, но зачастую и необходимость в современной разработке программного обеспечения. Это делает ваши приложения более надежными, простыми для понимания и менее подверженными ошибкам.

Понимая основные принципы и реализуя упомянутые выше стратегии, вы будете на пути к написанию более надежного кода.


Также опубликовано здесь


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE