Skip to content

Instantly share code, notes, and snippets.

@ugleiton
Last active January 26, 2023 19:52
Show Gist options
  • Save ugleiton/bc17d61602f236b515c07c7c54b9e641 to your computer and use it in GitHub Desktop.
Save ugleiton/bc17d61602f236b515c07c7c54b9e641 to your computer and use it in GitHub Desktop.
Mongo Lock
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "d9412b7f-6812-40ce-97dd-a6e9e3c59101",
"metadata": {
"tags": []
},
"source": [
"### LOCK DISTRIBUIDO COM PYTHON E MONGO\n",
"\n",
"Para utilizar esse recurso foi criada uma collection no mongo com índice único para chaves de locks, essas chaves são excluidas automaticamente ao finalizar algum procedimento.\n",
"\n",
"Por segurança foi criado um índice ttl no mongo com isso as chaves que não forem excluídas pelo python serão excluídas automaticamente pelo mongo depois de 2 minutos."
]
},
{
"cell_type": "markdown",
"id": "d58adee5-6c77-4a66-8f7e-6881977530e4",
"metadata": {},
"source": [
"##### instalado a lib pymongo para conexão com mongodb"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "adf83294-2ea1-4c41-8505-5ce9b349e13d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: pymongo in /opt/conda/lib/python3.10/site-packages (4.3.3)\n",
"Requirement already satisfied: dnspython<3.0.0,>=1.16.0 in /opt/conda/lib/python3.10/site-packages (from pymongo) (2.3.0)\n",
"Note: you may need to restart the kernel to use updated packages.\n"
]
}
],
"source": [
"%pip install pymongo"
]
},
{
"cell_type": "markdown",
"id": "2a265728-65ee-4c37-b0bf-1eba2da9a6aa",
"metadata": {
"tags": []
},
"source": [
"### Criando os índices na collection lock para o database teste\n",
"\n",
"##### indice *key* para montar a chave do lock para se tornar único\n",
"\n",
"##### indice *created_at* é um ttl usado para o mongo excluir o registro automaticamente depois de 120 segundos"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "17895284-bf4e-4ac7-b8fb-8b01506102a5",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'created_at_1'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from pymongo import MongoClient\n",
"mongo_client = MongoClient('localhost', 27017)\n",
"db = mongo_client['teste']\n",
"db.lock.create_index([(\"key\", 1)],unique=True)\n",
"db.lock.create_index( [( \"created_at\", 1 )], expireAfterSeconds= 120 )"
]
},
{
"cell_type": "markdown",
"id": "6ca89fbf-4939-411e-9a41-daa97795baf4",
"metadata": {},
"source": [
"### Criando classe para controle de lock usando formato 'with statement'\n",
"\n",
"##### com esse formato ao usar a classe com with o python irá executar automaticamente o método __enter__ antes dos códigos e o método __exit__ ao finalizar, veja o exemplo nos testes posteriormente\n",
"##### https://horadecodar.com.br/2020/04/20/para-que-serve-o-with-no-python-como-utilizar"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "c954c05f-837f-4c8e-b636-77d09ad680a7",
"metadata": {},
"outputs": [],
"source": [
"from pymongo.errors import DuplicateKeyError\n",
"import time\n",
"from datetime import datetime\n",
"class MongoLock():\n",
" def __init__(self, database: str, key: str):\n",
" self.database = database\n",
" self.key = key\n",
" \n",
" def __enter__(self):\n",
" while True:\n",
" try:\n",
" self.database.lock.insert_one({'key': self.key, 'created_at': datetime.utcnow()})\n",
" return self\n",
" except DuplicateKeyError:\n",
" print(f'waiting lock for key:{self.key}')\n",
"\n",
" def __exit__(self, type, value, traceback):\n",
" self.database.lock.delete_one({'key': self.key})"
]
},
{
"cell_type": "markdown",
"id": "74156a28-fd30-410d-b3a9-e52f11efcaa2",
"metadata": {},
"source": [
"### Testes usando threads que para simular um ambiente distribuído"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "9a23d1c5-6640-4544-bfe5-30dcfe66259b",
"metadata": {},
"outputs": [],
"source": [
"from pymongo import MongoClient\n",
"mongo_client = MongoClient('localhost', 27017)\n",
"db = mongo_client['teste']\n",
"\n",
"def teste_lock(nome):\n",
" print(nome)\n",
" seller_id = 'coisinhadejesus'\n",
" sku = '0123456678'\n",
" with MongoLock(db, seller_id+sku) as m:\n",
" print(f\"passei pelo lock {nome}\")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "19646aba-7e06-4175-aa00-78f9b84b791b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"thread 1\n",
"thread 2\n",
"passei pelo lock thread 1\n",
"thread 3\n",
"thread 4\n",
"thread 5\n",
"waiting lock for key:coisinhadejesus0123456678\n",
"thread 6\n",
"waiting lock for key:coisinhadejesus0123456678\n",
"waiting lock for key:coisinhadejesus0123456678\n",
"passei pelo lock thread 5\n",
"waiting lock for key:coisinhadejesus0123456678\n",
"waiting lock for key:coisinhadejesus0123456678\n",
"passei pelo lock thread 3\n",
"waiting lock for key:coisinhadejesus0123456678\n",
"passei pelo lock thread 2\n",
"waiting lock for key:coisinhadejesus0123456678\n",
"waiting lock for key:coisinhadejesus0123456678\n",
"passei pelo lock thread 4\n",
"waiting lock for key:coisinhadejesus0123456678\n",
"passei pelo lock thread 6\n"
]
}
],
"source": [
"from threading import Thread\n",
"from time import sleep\n",
"\n",
"t1 = Thread(target = teste_lock, args=['thread 1'])\n",
"t2 = Thread(target = teste_lock, args=['thread 2'])\n",
"t3 = Thread(target = teste_lock, args=['thread 3'])\n",
"t4 = Thread(target = teste_lock, args=['thread 4'])\n",
"t5 = Thread(target = teste_lock, args=['thread 5'])\n",
"t6 = Thread(target = teste_lock, args=['thread 6'])\n",
"\n",
"t1.start()\n",
"t2.start()\n",
"t3.start()\n",
"t4.start()\n",
"t5.start()\n",
"t6.start()\n",
"\n",
"sleep(0.2)\n",
"\n",
"t1.join()\n",
"t2.join()\n",
"t3.join()\n",
"t4.join()\n",
"t5.join()\n",
"t6.join()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "01fc89a4-81a2-4c45-86b8-6dfec999c5a8",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.8"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment