|
8 | 8 |
|
9 | 9 | from .error import DatabaseError, OperationalError, ProgrammingError, SqlSyntaxError |
10 | 10 | from .helper import SQLHelper |
| 11 | +from .retry import execute_with_retry |
11 | 12 | from .sql.delete_builder import DeleteExecutionPlan |
12 | 13 | from .sql.insert_builder import InsertExecutionPlan |
13 | 14 | from .sql.parser import SQLParser |
|
17 | 18 | _logger = logging.getLogger(__name__) |
18 | 19 |
|
19 | 20 |
|
| 21 | +def _run_db_command(db: Any, command: Dict[str, Any], connection: Any, operation_name: str) -> Dict[str, Any]: |
| 22 | + """Run a MongoDB command with optional transaction session and retry policy.""" |
| 23 | + retry_config = getattr(connection, "retry_config", None) |
| 24 | + |
| 25 | + if connection and connection.session and connection.session.in_transaction: |
| 26 | + return execute_with_retry( |
| 27 | + lambda: db.command(command, session=connection.session), |
| 28 | + retry_config, |
| 29 | + operation_name, |
| 30 | + ) |
| 31 | + |
| 32 | + return execute_with_retry( |
| 33 | + lambda: db.command(command), |
| 34 | + retry_config, |
| 35 | + operation_name, |
| 36 | + ) |
| 37 | + |
| 38 | + |
20 | 39 | @dataclass |
21 | 40 | class ExecutionContext: |
22 | 41 | """Manages execution context for a single query""" |
@@ -156,11 +175,8 @@ def _execute_find_plan( |
156 | 175 |
|
157 | 176 | _logger.debug(f"Executing MongoDB command: {find_command}") |
158 | 177 |
|
159 | | - # Execute find command with session if in transaction |
160 | | - if connection and connection.session and connection.session.in_transaction: |
161 | | - result = db.command(find_command, session=connection.session) |
162 | | - else: |
163 | | - result = db.command(find_command) |
| 178 | + # Execute find command with retry for transient system-level errors |
| 179 | + result = _run_db_command(db, find_command, connection, "find command") |
164 | 180 |
|
165 | 181 | # Create command result |
166 | 182 | return result |
@@ -214,11 +230,13 @@ def _execute_aggregate_plan( |
214 | 230 | # Get collection and call aggregate() |
215 | 231 | collection = db[execution_plan.collection] |
216 | 232 |
|
217 | | - # Execute aggregate with options |
218 | | - cursor = collection.aggregate(pipeline, **options) |
219 | | - |
220 | | - # Convert cursor to list |
221 | | - results = list(cursor) |
| 233 | + # Execute aggregate with retry for transient system-level errors |
| 234 | + retry_config = getattr(connection, "retry_config", None) |
| 235 | + results = execute_with_retry( |
| 236 | + lambda: list(collection.aggregate(pipeline, **options)), |
| 237 | + retry_config, |
| 238 | + "aggregate command", |
| 239 | + ) |
222 | 240 |
|
223 | 241 | # Apply additional filters if specified (from WHERE clause) |
224 | 242 | if execution_plan.filter_stage: |
@@ -420,11 +438,7 @@ def _execute_execution_plan( |
420 | 438 |
|
421 | 439 | _logger.debug(f"Executing MongoDB insert command: {command}") |
422 | 440 |
|
423 | | - # Execute with session if in transaction |
424 | | - if connection and connection.session and connection.session.in_transaction: |
425 | | - return db.command(command, session=connection.session) |
426 | | - else: |
427 | | - return db.command(command) |
| 441 | + return _run_db_command(db, command, connection, "insert command") |
428 | 442 | except PyMongoError as e: |
429 | 443 | _logger.error(f"MongoDB insert failed: {e}") |
430 | 444 | raise DatabaseError(f"Insert execution failed: {e}") |
@@ -504,11 +518,7 @@ def _execute_execution_plan( |
504 | 518 |
|
505 | 519 | _logger.debug(f"Executing MongoDB delete command: {command}") |
506 | 520 |
|
507 | | - # Execute with session if in transaction |
508 | | - if connection and connection.session and connection.session.in_transaction: |
509 | | - return db.command(command, session=connection.session) |
510 | | - else: |
511 | | - return db.command(command) |
| 521 | + return _run_db_command(db, command, connection, "delete command") |
512 | 522 | except PyMongoError as e: |
513 | 523 | _logger.error(f"MongoDB delete failed: {e}") |
514 | 524 | raise DatabaseError(f"Delete execution failed: {e}") |
@@ -608,11 +618,7 @@ def _execute_execution_plan( |
608 | 618 |
|
609 | 619 | _logger.debug(f"Executing MongoDB update command: {command}") |
610 | 620 |
|
611 | | - # Execute with session if in transaction |
612 | | - if connection and connection.session and connection.session.in_transaction: |
613 | | - return db.command(command, session=connection.session) |
614 | | - else: |
615 | | - return db.command(command) |
| 621 | + return _run_db_command(db, command, connection, "update command") |
616 | 622 | except PyMongoError as e: |
617 | 623 | _logger.error(f"MongoDB update failed: {e}") |
618 | 624 | raise DatabaseError(f"Update execution failed: {e}") |
|
0 commit comments