Таблица хранения Azure [Python] - Пакет не дает сбоя

В настоящее время я занимаюсь разработкой приложения Python (2.7), которое использует службу хранилища таблиц Azure через пакет Azure Python. Насколько я читал из REST API Azure, пакетные операции создают атомарные транзакции. Таким образом, если одна из операций завершается неудачей, весь пакет завершается неудачно, и никакие операции не выполняются.

Проблема, с которой я столкнулся, заключается в следующем: метод, указанный ниже, получает через параметр "rows" список диктов. У некоторых есть набор ETag (предоставленный из предыдущего запроса).

Если ETag установлен,попытайтесь выполнить операцию слияния. В противном случае, попробуйте операцию вставки. Поскольку существует несколько процессов, которые могут изменять одну и ту же сущность, необходимо решить проблему параллелизма с помощью параметра if_match функции merge_entity. Если операции слияния / вставки являются отдельными операциями (не включенными в пакет), система работает должным образом, вызывая исключение, если ETag не совпадают. К сожалению, этого не происходит, если они заключены в вызовы "begin_batch" / "commit_batch". Объекты объединяются (ошибочно), даже если ETag НЕ совпадают.

Я предоставил ниже и код и используемый тестовый пример. Также провел несколько ручных тестов несколько раз с тем же выводом.

Я не уверен, как подойти к этой проблеме. Я делаю что-то не так или это проблема с пакетом Python?

Используемый код следующий:

def persist_entities(self, rows):
    success = True
    self._service.begin_batch()        #If commented, works as expected (fails)
    for row in rows:
        print row
        etag = row.pop("ETag")
        if not etag:
            self._service.insert_entity(self._name,
                                        entity=row)
        else:
            print "Merging " + etag
            self._service.merge_entity(self._name,
                                       row["PartitionKey"],
                                       row["RowKey"],
                                       row, if_match=etag)
    try:            #Also tried with the try at the begining of the code
        self._service.commit_batch()       #If commented, works as expected (fails)
    except WindowsAzureError:
        print "Failed to merge"
        self._service.cancel_batch()
        success = False
    return success

Используемый тестовый пример:

def test_fail_update(self):
        service = self._conn.get_service()
        partition, new_rows = self._generate_data()   #Partition key and list of dicts
        success = self._wrapper.persist_entities(new_rows)   #Inserts fresh new entity
        ok_(success)                                           #Insert succeeds
        rows = self._wrapper.get_entities_by_row(partition) #Retreives inserted data for ETag
        eq_(len(rows), 1)
        for index in rows:
            row = rows[index]
            data = new_rows[0]
            data["Count"] = 155                       #Same data, different value
            data["ETag"] = "random_etag"              #Change ETag to a random string
            val = self._wrapper.persist_entities([data])              #Try to merge
            ok_(not val)            #val = True for merge success, False for merge fail.
            #It's always True when operations in batch. False if operations out of batch 
            rows1 = self._wrapper.get_entities_by_row(partition)
            eq_(len(rows1), 1)
            eq_(rows1[index].Count, 123)
            break

    def _generate_data(self):
        date = datetime.now().isoformat()
        partition = "{0}_{1}_{2}".format("1",
                                         Stats.RESOLUTION_DAY, date)
        data = {
            "PartitionKey": partition,
            "RowKey": "viewitem",
            "Count": 123,
            "ETag": None
        }
        return partition, [data]

2 ответа

Решение

Это ошибка в SDK (v0.8 и ранее). Я создал проблему и проверил исправление. Это будет частью следующего релиза. Вы можете установить pip из git repo, чтобы проверить исправление. https://github.com/Azure/azure-sdk-for-python/issues/149

В хранилище таблиц Azure есть новая библиотека python в предварительной версии, которая доступна для установки через pip. Для установки используйте следующую команду pip

      pip install azure-data-tables

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

  1. Пакетная операция может быть зафиксирована только для объектов, содержащих один и тот же ключ раздела.
  2. Пакетная операция не может содержать несколько операций с одним и тем же ключом строки.
  3. Пакеты будут зафиксированы только в том случае, если весь пакет будет успешным, если send_batch выдает ошибку, обновлений делать не будет.

При этом операции создания и обновления работают так же, как и создание и обновление без пакетной обработки. Например:

      from azure.data.tables import TableClient, UpdateMode
table_client = TableClient.from_connection_string(conn_str, table_name="myTable")

batch = table_client.create_batch()
batch.create_entity(entity1)
batch.update_entity(entity2, etag=etag, match_condition=UpdateMode.MERGE)
batch.delete_entity(entity['PartitionKey'], entity['RowKey'])

try:
    table_client.send_batch(batch)
except BatchErrorException as e:
    print("There was an error with the batch")
    print(e)

Дополнительные образцы с новой библиотекой можно найти на странице образцов в репозитории.

(К вашему сведению, я сотрудник Microsoft в команде Azure SDK для Python)

Другие вопросы по тегам