Я тестирую 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'}
пожалуйста, помогите мне как сделатьсинхронизируйте этот вызов, чтобы у каждого запроса было уникальное имя записной книжки.