Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Introduce wallet exchange 🗃️ #7033

Open
wants to merge 19 commits into
base: master
Choose a base branch
from

Conversation

matusdrobuliak66
Copy link
Contributor

@matusdrobuliak66 matusdrobuliak66 commented Jan 13, 2025

What do these changes do?

Currently, a project's connected wallet can go into a negative balance. This occurs because we have a policy to avoid interrupting users' computational jobs when their wallet reaches 0 credits—only dynamic services are stopped.

This PR:

  • 🐛 Fixes a bug that prevents users from changing a project's wallet when the project is in DEBT.
    • A project is considered IN DEBT if the wallet connected to it has a balance below 0 credits.
    • Users can resolve this in two ways:
      • Top up credits to the wallet connected to the project.
      • Use a different wallet to pay off the project's debt.

Example:
The project transaction is in debt:

image

After the user pays off the debt using another wallet (triggering 2 new transactions between the wallets), the project transaction status changes from IN_DEBT to BILLED, unblocking the project.

image

Related issue/s

How to test

Dev-ops checklist

Copy link

codecov bot commented Jan 13, 2025

Codecov Report

Attention: Patch coverage is 79.79452% with 59 lines in your changes missing coverage. Please review.

Project coverage is 85.27%. Comparing base (3d01781) to head (61bbbf9).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #7033      +/-   ##
==========================================
- Coverage   87.57%   85.27%   -2.30%     
==========================================
  Files        1629     1574      -55     
  Lines       63454    62079    -1375     
  Branches     2047     1794     -253     
==========================================
- Hits        55569    52940    -2629     
- Misses       7549     8828    +1279     
+ Partials      336      311      -25     
Flag Coverage Δ
integrationtests 63.73% <43.03%> (-0.04%) ⬇️
unittests 83.62% <79.79%> (-2.35%) ⬇️
Components Coverage Δ
api 76.84% <ø> (ø)
pkg_aws_library ∅ <ø> (∅)
pkg_dask_task_models_library ∅ <ø> (∅)
pkg_models_library 91.46% <100.00%> (+<0.01%) ⬆️
pkg_notifications_library 84.57% <ø> (ø)
pkg_postgres_database 88.31% <100.00%> (+0.01%) ⬆️
pkg_service_integration 70.02% <ø> (ø)
pkg_service_library 73.48% <0.00%> (-0.41%) ⬇️
pkg_settings_library ∅ <ø> (∅)
pkg_simcore_sdk 85.38% <ø> (ø)
agent 96.45% <ø> (ø)
api_server 90.54% <ø> (ø)
autoscaling 96.09% <ø> (ø)
catalog 90.66% <ø> (ø)
clusters_keeper 99.24% <ø> (ø)
dask_sidecar 91.26% <ø> (ø)
datcore_adapter 93.18% <ø> (ø)
director 76.42% <ø> (-0.09%) ⬇️
director_v2 91.30% <ø> (ø)
dynamic_scheduler 97.21% <ø> (ø)
dynamic_sidecar 89.75% <ø> (ø)
efs_guardian 90.30% <0.00%> (-0.17%) ⬇️
invitations 93.44% <ø> (ø)
osparc_gateway_server ∅ <ø> (∅)
payments 92.66% <ø> (ø)
resource_usage_tracker 89.15% <90.17%> (-0.31%) ⬇️
storage 89.57% <ø> (ø)
webclient ∅ <ø> (∅)
webserver 79.03% <87.34%> (-6.92%) ⬇️

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3d01781...61bbbf9. Read the comment docs.

@matusdrobuliak66 matusdrobuliak66 self-assigned this Jan 13, 2025
@matusdrobuliak66 matusdrobuliak66 added this to the Singularity milestone Jan 13, 2025
@matusdrobuliak66 matusdrobuliak66 changed the title ✨ Introduce wallet exchange ✨ Introduce wallet exchange 🗃️ Jan 14, 2025
@matusdrobuliak66 matusdrobuliak66 added a:webserver issue related to the webserver service a:resource-usage-tracker resource usage tracker service labels Jan 16, 2025
Copy link
Member

@odeimaiz odeimaiz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌

Copy link
Member

@sanderegg sanderegg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good, but the change in the efs-guardian. I would like to discuss this.

@@ -38,16 +38,50 @@ class ServiceRunStatus(StrAutoEnum):


class CreditTransactionStatus(StrAutoEnum):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: this is always in sync with CreditTransactionStatus in resource_tracker_credit_transactions.py? do you test this?
Q: same thing with CreditClassification

Comment on lines +48 to 53
# pagination
offset: int = 0,
limit: int = 20,
# ordering
order_by: OrderBy | None = None,
) -> ServiceRunPage:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these comments really useful? pagination, well I'd say it is pretty clear already. and ordering for something called order_by. I'd'say that is not necessary.

Comment on lines 47 to 54
)
except DBProjectNotFoundError as exc:
_logger.warning(
"Project %s not found, this should not happen, please investigate (contact MD)",
exc.msg_template,
except DBProjectNotFoundError:
_logger.info(
"Project %s not found. Removing EFS data for project {project_id} started",
project_id,
)
await efs_manager.remove_project_efs_data(project_id)
if (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks like a weird merge and looks wrong. can we discuss that one?

Comment on lines +202 to +213
# attribute filtering
service_run_status: ServiceRunStatus | None = None,
started_from: datetime | None = None,
started_until: datetime | None = None,
transaction_status: CreditTransactionStatus | None = None,
project_id: ProjectID | None = None,
# pagination
offset: int,
limit: int,
# ordering
order_by: OrderBy | None = None,
) -> list[ServiceRunWithCreditsDB]:
async with transaction_context(engine, connection) as conn:
query = (
) -> tuple[int, list[ServiceRunWithCreditsDB]]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so I see this is a new pattern.
I would propose the following instead of adding comments like these everywhere:

filter_by_service_run_status
filter_by_started_from
filter_by_started_until
page_offset
page_limit
order_by

product_name: ProductName,
wallet_id: WalletID,
project_id: ProjectID,
transaction_status: CreditTransactionStatus | None = None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here you do not put #attribute filtering comment?
As I said I prefer not to have these kind of comments all over the place. usually that means that something is unclear.

new_wallet_transaction = CreditTransactionCreateBody(
product_name=product_name,
wallet_id=_WALLET_ID_FOR_PAYING_DEBT__NOT_ENOUGH_CREDITS,
wallet_name="new wallet",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

faker.name()

wallet_id=_WALLET_ID_FOR_PAYING_DEBT__NOT_ENOUGH_CREDITS,
wallet_name="new wallet",
user_id=_USER_ID_1,
user_email="[email protected]",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

faker.email()

@@ -240,7 +240,7 @@ async def test_process_event_functions(
postgres_db, msg.service_run_id, modified_at
)
assert output.osparc_credits < first_credits_used
assert output.transaction_status == "BILLED"
assert output.transaction_status == "IN_DEBT"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not using CreditTransactionStatus.IN_DEBT.value ?

@@ -127,6 +134,12 @@ async def open_project(request: web.Request) -> web.Response:
),
)

await projects_service.raise_if_project_is_in_debt(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check_project_financial_status ? ;)


class _PayProjectDebtBody(BaseModel):
amount: Annotated[Decimal, Field(lt=0)]
model_config = ConfigDict(extra="forbid")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: here I was under the assumption that we "accept clients that add stuff since we do not care and ignore whatever fields a client might add" and that we forbid for stuff we return. Or is there a reason to forbid any extra field?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a:resource-usage-tracker resource usage tracker service a:webserver issue related to the webserver service
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Issues when changing wallet after running out of credits
3 participants