Skip to content

Commit 8c81f52

Browse files
daily work
1 parent a8ca793 commit 8c81f52

File tree

16 files changed

+734
-208
lines changed

16 files changed

+734
-208
lines changed

packages/models-library/src/models_library/resource_tracker.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,34 @@ class ServiceRunStatus(StrAutoEnum):
3838

3939

4040
class CreditTransactionStatus(StrAutoEnum):
41+
# Represents the possible statuses of a credit transaction.
42+
4143
PENDING = auto()
44+
# The transaction is pending and has not yet been finalized.
45+
# Example: During the running of a service, the transaction remains in the Pending state until the service is stopped.
46+
4247
BILLED = auto()
48+
# The transaction has been successfully billed.
49+
50+
IN_DEBT = auto()
51+
# The transaction is marked as in debt.
52+
# Example: This occurs when a computational job continues to run even though the user does not have sufficient credits in their wallet.
53+
4354
NOT_BILLED = auto()
55+
# The transaction will not be billed.
56+
# Example: This status is used when there is an issue on our side, and we decide not to bill the user.
57+
4458
REQUIRES_MANUAL_REVIEW = auto()
59+
# The transaction requires manual review due to potential issues.
60+
# NOTE: This status is currently not in use.
4561

4662

4763
class CreditClassification(StrAutoEnum):
4864
ADD_WALLET_TOP_UP = auto() # user top up credits
4965
DEDUCT_SERVICE_RUN = auto() # computational/dynamic service run costs)
5066
DEDUCT_LICENSE_PURCHASE = auto()
67+
ADD_WALLET_EXCHANGE = auto()
68+
DEDUCT_WALLET_EXCHANGE = auto()
5169

5270

5371
class PricingPlanClassification(StrAutoEnum):
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import logging
2+
from typing import Final
3+
4+
from models_library.api_schemas_resource_usage_tracker import (
5+
RESOURCE_USAGE_TRACKER_RPC_NAMESPACE,
6+
)
7+
from models_library.api_schemas_resource_usage_tracker.credit_transactions import (
8+
CreditTransactionCreateBody,
9+
WalletTotalCredits,
10+
)
11+
from models_library.products import ProductName
12+
from models_library.projects import ProjectID
13+
from models_library.rabbitmq_basic_types import RPCMethodName
14+
from models_library.resource_tracker import CreditTransactionStatus
15+
from models_library.wallets import WalletID
16+
from pydantic import NonNegativeInt, TypeAdapter
17+
18+
from ....logging_utils import log_decorator
19+
from ....rabbitmq import RabbitMQRPCClient
20+
21+
_logger = logging.getLogger(__name__)
22+
23+
24+
_DEFAULT_TIMEOUT_S: Final[NonNegativeInt] = 20
25+
26+
_RPC_METHOD_NAME_ADAPTER: TypeAdapter[RPCMethodName] = TypeAdapter(RPCMethodName)
27+
28+
29+
@log_decorator(_logger, level=logging.DEBUG)
30+
async def get_wallet_total_credits(
31+
rabbitmq_rpc_client: RabbitMQRPCClient,
32+
*,
33+
product_name: ProductName,
34+
wallet_id: WalletID,
35+
transaction_status: CreditTransactionStatus | None = None,
36+
project_id: ProjectID | None = None,
37+
) -> WalletTotalCredits:
38+
result = await rabbitmq_rpc_client.request(
39+
RESOURCE_USAGE_TRACKER_RPC_NAMESPACE,
40+
_RPC_METHOD_NAME_ADAPTER.validate_python("get_wallet_total_credits"),
41+
product_name=product_name,
42+
wallet_id=wallet_id,
43+
transaction_status=transaction_status,
44+
project_id=project_id,
45+
timeout_s=_DEFAULT_TIMEOUT_S,
46+
)
47+
assert isinstance(result, WalletTotalCredits) # nosec
48+
return result
49+
50+
51+
@log_decorator(_logger, level=logging.DEBUG)
52+
async def pay_project_debt(
53+
rabbitmq_rpc_client: RabbitMQRPCClient,
54+
*,
55+
project_id: ProjectID,
56+
current_wallet_transaction: CreditTransactionCreateBody,
57+
new_wallet_transaction: CreditTransactionCreateBody,
58+
) -> None:
59+
result = await rabbitmq_rpc_client.request(
60+
RESOURCE_USAGE_TRACKER_RPC_NAMESPACE,
61+
_RPC_METHOD_NAME_ADAPTER.validate_python("pay_project_debt"),
62+
project_id=project_id,
63+
current_wallet_transaction=current_wallet_transaction,
64+
new_wallet_transaction=new_wallet_transaction,
65+
timeout_s=_DEFAULT_TIMEOUT_S,
66+
)
67+
assert isinstance(result, None) # nosec
68+
return result

services/efs-guardian/src/simcore_service_efs_guardian/services/background_tasks.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,12 @@ async def removal_policy_task(app: FastAPI) -> None:
4545
_project_last_change_date = (
4646
await projects_repo.get_project_last_change_date(project_id)
4747
)
48-
except DBProjectNotFoundError as exc:
49-
_logger.warning(
50-
"Project %s not found, this should not happen, please investigate (contact MD)",
51-
exc.msg_template,
48+
except DBProjectNotFoundError:
49+
_logger.info(
50+
"Project %s not found. Removing EFS data for project {project_id} started",
51+
project_id,
5252
)
53+
await efs_manager.remove_project_efs_data(project_id)
5354
if (
5455
_project_last_change_date
5556
< base_start_timestamp
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from fastapi import FastAPI
2+
from models_library.api_schemas_resource_usage_tracker.credit_transactions import (
3+
CreditTransactionCreateBody,
4+
WalletTotalCredits,
5+
)
6+
from models_library.products import ProductName
7+
from models_library.projects import ProjectID
8+
from models_library.resource_tracker import CreditTransactionStatus
9+
from models_library.wallets import WalletID
10+
from servicelib.rabbitmq import RPCRouter
11+
12+
from ...services import credit_transactions
13+
14+
router = RPCRouter()
15+
16+
17+
@router.expose(reraise_if_error_type=())
18+
async def get_wallet_total_credits(
19+
app: FastAPI,
20+
*,
21+
product_name: ProductName,
22+
wallet_id: WalletID,
23+
# internal filters
24+
transaction_status: CreditTransactionStatus | None = None,
25+
project_id: ProjectID | None = None,
26+
) -> WalletTotalCredits:
27+
return await credit_transactions.sum_credit_transactions_by_product_and_wallet(
28+
db_engine=app.state.engine,
29+
product_name=product_name,
30+
wallet_id=wallet_id,
31+
transaction_status=transaction_status,
32+
project_id=project_id,
33+
)
34+
35+
36+
@router.expose(reraise_if_error_type=())
37+
async def pay_project_debt(
38+
app: FastAPI,
39+
*,
40+
project_id: ProjectID,
41+
current_wallet_transaction: CreditTransactionCreateBody,
42+
new_wallet_transaction: CreditTransactionCreateBody,
43+
) -> None:
44+
return await credit_transactions.pay_project_debt(
45+
db_engine=app.state.engine,
46+
rabbitmq_client=app.state.rabbitmq_client,
47+
project_id=project_id,
48+
current_wallet_transaction=current_wallet_transaction,
49+
new_wallet_transaction=new_wallet_transaction,
50+
)
Lines changed: 1 addition & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@
44
PricingPlanToServiceGet,
55
PricingUnitGet,
66
)
7-
from models_library.api_schemas_resource_usage_tracker.service_runs import (
8-
OsparcCreditsAggregatedUsagesPage,
9-
ServiceRunPage,
10-
)
117
from models_library.products import ProductName
128
from models_library.resource_tracker import (
139
PricingPlanCreate,
@@ -16,108 +12,15 @@
1612
PricingUnitId,
1713
PricingUnitWithCostCreate,
1814
PricingUnitWithCostUpdate,
19-
ServiceResourceUsagesFilters,
20-
ServicesAggregatedUsagesTimePeriod,
21-
ServicesAggregatedUsagesType,
2215
)
23-
from models_library.rest_ordering import OrderBy
2416
from models_library.services import ServiceKey, ServiceVersion
25-
from models_library.users import UserID
26-
from models_library.wallets import WalletID
27-
from pydantic import AnyUrl
2817
from servicelib.rabbitmq import RPCRouter
2918

30-
from ...core.settings import ApplicationSettings
31-
from ...services import pricing_plans, pricing_units, service_runs
32-
from ...services.modules.s3 import get_s3_client
19+
from ...services import pricing_plans, pricing_units
3320

3421
router = RPCRouter()
3522

3623

37-
## Service runs
38-
39-
40-
@router.expose(reraise_if_error_type=())
41-
async def get_service_run_page(
42-
app: FastAPI,
43-
*,
44-
user_id: UserID,
45-
product_name: ProductName,
46-
limit: int = 20,
47-
offset: int = 0,
48-
wallet_id: WalletID | None = None,
49-
access_all_wallet_usage: bool = False,
50-
order_by: OrderBy | None = None,
51-
filters: ServiceResourceUsagesFilters | None = None,
52-
) -> ServiceRunPage:
53-
return await service_runs.list_service_runs(
54-
user_id=user_id,
55-
product_name=product_name,
56-
db_engine=app.state.engine,
57-
limit=limit,
58-
offset=offset,
59-
wallet_id=wallet_id,
60-
access_all_wallet_usage=access_all_wallet_usage,
61-
order_by=order_by,
62-
filters=filters,
63-
)
64-
65-
66-
@router.expose(reraise_if_error_type=())
67-
async def export_service_runs(
68-
app: FastAPI,
69-
*,
70-
user_id: UserID,
71-
product_name: ProductName,
72-
wallet_id: WalletID | None = None,
73-
access_all_wallet_usage: bool = False,
74-
order_by: OrderBy | None = None,
75-
filters: ServiceResourceUsagesFilters | None = None,
76-
) -> AnyUrl:
77-
app_settings: ApplicationSettings = app.state.settings
78-
s3_settings = app_settings.RESOURCE_USAGE_TRACKER_S3
79-
assert s3_settings # nosec
80-
81-
return await service_runs.export_service_runs(
82-
s3_client=get_s3_client(app),
83-
bucket_name=f"{s3_settings.S3_BUCKET_NAME}",
84-
s3_region=s3_settings.S3_REGION,
85-
user_id=user_id,
86-
product_name=product_name,
87-
db_engine=app.state.engine,
88-
wallet_id=wallet_id,
89-
access_all_wallet_usage=access_all_wallet_usage,
90-
order_by=order_by,
91-
filters=filters,
92-
)
93-
94-
95-
@router.expose(reraise_if_error_type=())
96-
async def get_osparc_credits_aggregated_usages_page(
97-
app: FastAPI,
98-
*,
99-
user_id: UserID,
100-
product_name: ProductName,
101-
aggregated_by: ServicesAggregatedUsagesType,
102-
time_period: ServicesAggregatedUsagesTimePeriod,
103-
limit: int = 20,
104-
offset: int = 0,
105-
wallet_id: WalletID,
106-
access_all_wallet_usage: bool = False,
107-
) -> OsparcCreditsAggregatedUsagesPage:
108-
return await service_runs.get_osparc_credits_aggregated_usages_page(
109-
user_id=user_id,
110-
product_name=product_name,
111-
db_engine=app.state.engine,
112-
aggregated_by=aggregated_by,
113-
time_period=time_period,
114-
limit=limit,
115-
offset=offset,
116-
wallet_id=wallet_id,
117-
access_all_wallet_usage=access_all_wallet_usage,
118-
)
119-
120-
12124
## Pricing plans
12225

12326

0 commit comments

Comments
 (0)