-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from resonatehq/tomas/dst-framework
Tomas/dst framework
- Loading branch information
Showing
17 changed files
with
399 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -160,4 +160,6 @@ cython_debug/ | |
#.idea/ | ||
|
||
# ruff | ||
.ruff_cache/ | ||
.ruff_cache/ | ||
|
||
*.db |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# python generated files | ||
__pycache__/ | ||
*.py[oc] | ||
build/ | ||
dist/ | ||
wheels/ | ||
*.egg-info | ||
|
||
# venv | ||
.venv |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"python.testing.pytestArgs": [ | ||
"tests" | ||
], | ||
"python.testing.unittestEnabled": false, | ||
"python.testing.pytestEnabled": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# race-condition | ||
|
||
Describe your project here. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
[project] | ||
name = "race-condition" | ||
version = "0.1.0" | ||
description = "Add your description here" | ||
authors = [ | ||
{ name = "Tomperez98", email = "[email protected]" } | ||
] | ||
dependencies = [ | ||
"resonate-sdk-py @ file:///Users/tomasperez/Documents/resonate/resonate-sdk-py/examples/race-condition/../..", | ||
"typing-extensions>=4.12.2", | ||
] | ||
readme = "README.md" | ||
requires-python = ">= 3.10" | ||
|
||
[build-system] | ||
requires = ["hatchling"] | ||
build-backend = "hatchling.build" | ||
|
||
[tool.rye.scripts] | ||
check-types = "dmypy run --timeout 60 -- src tests" | ||
|
||
[tool.rye] | ||
managed = true | ||
dev-dependencies = [ | ||
"pytest>=8.2.2", | ||
"mypy>=1.10.1", | ||
] | ||
|
||
[tool.hatch.metadata] | ||
allow-direct-references = true | ||
|
||
[tool.hatch.build.targets.wheel] | ||
packages = ["src/race_condition"] | ||
|
||
[tool.pytest.ini_options] | ||
testpaths = ["tests"] | ||
xfail_strict = true | ||
addopts = [ | ||
"--import-mode=importlib", | ||
"--log-cli-level=DEBUG" | ||
] | ||
|
||
[tool.ruff.lint.per-file-ignores] | ||
"tests/*.py" = ["INP001", "S101", "D"] | ||
|
||
[tool.mypy] | ||
mypy_path = "src" | ||
plugins = [] | ||
follow_imports = "normal" | ||
strict_optional = false | ||
warn_redundant_casts = true | ||
warn_unused_ignores = true | ||
disallow_any_generics = true | ||
check_untyped_defs = true | ||
warn_unused_configs = true | ||
disallow_subclassing_any = true | ||
disallow_incomplete_defs = true | ||
disallow_untyped_decorators = true | ||
disallow_untyped_calls = true | ||
disallow_untyped_defs = true | ||
explicit_package_bases = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# generated by rye | ||
# use `rye lock` or `rye sync` to update this lockfile | ||
# | ||
# last locked with the following flags: | ||
# pre: false | ||
# features: [] | ||
# all-features: false | ||
# with-sources: false | ||
|
||
-e file:. | ||
exceptiongroup==1.2.1 | ||
# via pytest | ||
iniconfig==2.0.0 | ||
# via pytest | ||
mypy==1.10.1 | ||
mypy-extensions==1.0.0 | ||
# via mypy | ||
packaging==24.1 | ||
# via pytest | ||
pluggy==1.5.0 | ||
# via pytest | ||
pytest==8.2.2 | ||
resonate-sdk-py @ file:///Users/tomasperez/Documents/resonate/resonate-sdk-py/examples/race-condition/../.. | ||
# via race-condition | ||
result==0.17.0 | ||
# via resonate-sdk-py | ||
tomli==2.0.1 | ||
# via mypy | ||
# via pytest | ||
typing-extensions==4.12.2 | ||
# via mypy | ||
# via race-condition |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# generated by rye | ||
# use `rye lock` or `rye sync` to update this lockfile | ||
# | ||
# last locked with the following flags: | ||
# pre: false | ||
# features: [] | ||
# all-features: false | ||
# with-sources: false | ||
|
||
-e file:. | ||
resonate-sdk-py @ file:///Users/tomasperez/Documents/resonate/resonate-sdk-py/examples/race-condition/../.. | ||
# via race-condition | ||
result==0.17.0 | ||
# via resonate-sdk-py | ||
typing-extensions==4.12.2 | ||
# via race-condition |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
from __future__ import annotations | ||
|
||
from sqlite3 import Connection | ||
from typing import TYPE_CHECKING, Any | ||
|
||
from resonate_sdk_py.scheduler.shared import Call, Yieldable | ||
|
||
if TYPE_CHECKING: | ||
from collections.abc import Generator | ||
|
||
from resonate_sdk_py.context import Context | ||
|
||
|
||
class NotEnoughMoneyError(Exception): | ||
def __init__(self, account_id: int) -> None: | ||
super().__init__(f"Account {account_id} does not have enough money") | ||
|
||
|
||
def get_current_balance(ctx: Context, conn: Connection, account_id: int) -> int: # noqa: ARG001 | ||
balance: int = conn.execute( | ||
"SELECT balance FROM accounts WHERE account_id = ?", (account_id,) | ||
).fetchone()[0] | ||
return balance | ||
|
||
|
||
def modify_balance( | ||
ctx: Context, | ||
conn: Connection, | ||
account_id: int, | ||
amount: int, | ||
) -> None: | ||
cur = conn.execute( | ||
""" | ||
UPDATE accounts | ||
SET balance = balance + ? | ||
WHERE account_id = ? | ||
""", | ||
(amount, account_id), | ||
) | ||
|
||
ctx.assert_statement(cur.rowcount == 1, msg="More that one row was affected") | ||
|
||
|
||
def transaction( | ||
ctx: Context, conn: Connection, source: int, target: int, amount: int | ||
) -> Generator[Yieldable, Any, None]: | ||
source_balance: int = yield Call( | ||
ctx, get_current_balance, conn=conn, account_id=source | ||
) | ||
|
||
if source_balance - amount < 0: | ||
raise NotEnoughMoneyError(account_id=source) | ||
|
||
yield Call( | ||
ctx, | ||
modify_balance, | ||
conn=conn, | ||
account_id=source, | ||
amount=amount * -1, | ||
) | ||
|
||
yield Call( | ||
ctx, | ||
modify_balance, | ||
conn=conn, | ||
account_id=target, | ||
amount=amount, | ||
) | ||
conn.commit() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
from __future__ import annotations | ||
|
||
import sqlite3 | ||
from functools import partial | ||
from typing import TYPE_CHECKING | ||
|
||
import pytest | ||
import race_condition | ||
import resonate_sdk_py | ||
|
||
if TYPE_CHECKING: | ||
from collections.abc import Generator | ||
|
||
from resonate_sdk_py.scheduler.dst import DSTScheduler | ||
|
||
|
||
@pytest.fixture() | ||
def setup_and_teardown() -> Generator[sqlite3.Connection, None, None]: | ||
conn = sqlite3.connect("test.db") | ||
ans = conn.execute("SELECT 1").fetchone() | ||
assert ans == (1,) | ||
conn.execute("DROP TABLE IF EXISTS accounts") | ||
conn.execute("CREATE TABLE accounts(account_id, balance)") | ||
conn.execute( | ||
""" | ||
INSERT INTO accounts VALUES | ||
(1, 100), | ||
(2, 0) | ||
""" | ||
) | ||
conn.commit() | ||
yield conn | ||
|
||
|
||
@pytest.mark.parametrize("scheduler", resonate_sdk_py.testing.dst([963, 20, range(3)])) | ||
def test_race_condition( | ||
scheduler: DSTScheduler, | ||
setup_and_teardown: sqlite3.Connection, | ||
) -> None: | ||
conn = setup_and_teardown | ||
|
||
_ = scheduler.run( | ||
[ | ||
partial( | ||
race_condition.transaction, | ||
conn=conn, | ||
source=1, | ||
target=2, | ||
amount=100, | ||
), | ||
partial( | ||
race_condition.transaction, | ||
conn=conn, | ||
source=1, | ||
target=2, | ||
amount=70, | ||
), | ||
] | ||
) | ||
|
||
source_balance: int = conn.execute( | ||
"SELECT balance FROM accounts WHERE account_id = 1" | ||
).fetchone()[0] | ||
target_balance: int = conn.execute( | ||
"SELECT balance FROM accounts WHERE account_id = 2" | ||
).fetchone()[0] | ||
|
||
assert ( | ||
source_balance == 0 and target_balance == 100 | ||
), f"Seed {scheduler.seed} causes a failure" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
from __future__ import annotations | ||
|
||
from . import testing | ||
|
||
def hello() -> str: | ||
return "Hello from resonate-sdk-py!" | ||
__all__ = ["testing"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.