синхронизировать параллельные запросы для вызова API - PullRequest
0 голосов
/ 06 декабря 2018

Я тестирую API, в котором я отправляю асинхронный запрос к API. Я попробовал три способа асинхронной отправки запросов, все опции, которые я упомянул в следующем тестовом примере:

def test_generate_name_of_notebook(mock_create_notebook, mock_get_request, mock_running_notebooks, client,capsys):
# prepare data
input_data = {
    "description": "test",
    "docker_image_id": docker_image.id,
    "path": "string",
    "tags": [
        "project=123",
        "label = test"
    ]
}

# hit the api 
#1st option
# import threading
# Thread1 = threading.Thread(target=hit_api(client, input_data))
# Thread2 = threading.Thread(target=hit_api(client, input_data))
# Thread3 = threading.Thread(target=hit_api(client, input_data))
# Thread4 = threading.Thread(target=hit_api(client, input_data))

# Thread1.start()
# Thread2.start()
# Thread3.start()
# Thread4.start()

# Thread1.join()
# Thread2.join()
# Thread3.join()
# Thread4.join()

#2nd option:
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
    futures = {executor.submit(hit_api, client, input_data),executor.submit(hit_api, client, input_data),executor.submit(hit_api, client, input_data),executor.submit(hit_api, client, input_data)}
    concurrent.futures.wait(futures)

#3rd option
# loop = asyncio.get_event_loop()
# loop.run_until_complete(asyncio.gather(hit_api(client,input_data), hit_api(client,input_data), hit_api(client,input_data), hit_api(client,input_data)))

# verify response
assert response.status_code == 200
assert mock_create_notebook.is_called_once
assert mock_get_request.is_called_once
assert mock_running_notebooks.is_called_once  

def hit_api(client,input_data):
    # hit the api
    timestamp = datetime.datetime.now()
    response = client.post(append_url_prefix("v1/notebooks"), json=input_data)
    print("{} : {} ".format(timestamp, response))
    with open("copy.txt", "a") as file:
        file.write("{}: {}\n".format(timestamp, response.json))
        file.write("{}: ========== \n".format(timestamp))
        file.write(" \n")

---------------------------------------------------------------------------------------------

Этофункция, которую я вызываю из тестового примера

def create_api():
"""
API to create notebook
"""
# parse data
data = request.get_json()

# create notebook object
notebook = create_notebook(data)

----------------------------------------------------------------------------------------------

Это функция create_notebook. Здесь я синхронизирую запросы с помощью синхронизатора decorator. Это вызовет функцию generate_name, если name не присутствует в данных для создания блокнота.

 @synchronized
 @trace(logger=log)
 def create_notebook(data):

"""
Create notebook and tags

Args:
    data (dict): Dictionary of data
"""

# generate name
if "name" not in data:
    name = generate_name(tags)

data.update({"name": name})  

# create notebook object
log.debug("Creating notebook object")
notebook = Notebook(**data)

# save notebook object
db.session.add(notebook)
db.session.commit()

return notebook

----------------------------------------------------------------------------------------------

Это функция generate_name, которая извлекает фамилию, присутствующую в базе данных, и увеличивает счетчик для создания нового имени.

@trace(logger=log)
def generate_name(tags):
""" Generate random name for notebook """

name = "untitled-1"

notebook = db.session \
    .query(Notebook) \
    .join(NotebookTag, Notebook.id == NotebookTag.notebook_id) \
    .filter(NotebookTag.tag.in_([project])) \
    .filter(Notebook.name.like("untitled-%")) \
    .order_by(desc(Notebook.created_on)) \
    .first()

log.debug("Last notebook=%s", notebook)

if notebook:
    count = notebook.name.split("-")[1].split(".")[0]
    count = int(count) + 1
    name = "untitled-{}".format(count)
return name

----------------------------------------------------------------------------------------------

синхронизированный декоратор

def synchronized(func):
func.__lock__ = threading.Lock()

def synced_func(*args, **kws):
    with func.__lock__:
        return func(*args, **kws)

return synced_func

----------------------------------------------------------------------------------------------

вывод: использование синхронизации декоратора.где я получаю одно и то же имя ноутбука даже после применения декоратора синхронизации к функции create_notebook.

2018-12-06 16:55:23.618141: {'id': 'ccd59750-f9a8-49ae-bbcc- 
4a859e0598e6', 'name': 'untitled-1.ipynb'}

2018-12-06 16:55:23.617511: {'id': '82721a68-cbe3-46fe-b366- 
c7e549543427', 'name': 'untitled-2.ipynb'}

2018-12-06 16:55:23.618698: {'id': '90c40fd0-82f9-4c29-b650- 
bb35be4f9fb2', 'name': 'untitled-2.ipynb'}

2018-12-06 16:55:23.619334: {'id': '4ee797bc-5ebd-493c-b60f- 
ca1b7da14f3f', 'name': 'untitled-3.ipynb'}

----------------------------------------------------------------------------------------------

вывод: без использования синхронизации декоратора

2018-12-06 16:56:28.379844: {'id': '92108a64-b3ec-4aa5-8381- 
3a986964b7ab', 'name': 'untitled-1.ipynb'}

2018-12-06 16:56:28.378486: {'id': 'f81f667a-ba21-4d70-8f40- 
923b20e06f11', 'name': 'untitled-1.ipynb'}

2018-12-06 16:56:28.380882: {'id': '65c38a7f-f6c6-42fa-b606- 
b9ea5cab2fce', 'name': 'untitled-1.ipynb'}

2018-12-06 16:56:28.382197: {'id': 'cf5f386e-56df-4f05-8c85- 
8db063c7d57f', 'name': 'untitled-1.ipynb'}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...