Skip to content

Added logging during Ventis deploy logs#13

Closed
Saaketh0 wants to merge 18 commits into
mainfrom
ventis-build-logs
Closed

Added logging during Ventis deploy logs#13
Saaketh0 wants to merge 18 commits into
mainfrom
ventis-build-logs

Conversation

@Saaketh0

@Saaketh0 Saaketh0 commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Currently, when ventis deploy is running and docker container is run from global controller to a local controller, there is no logging if that command fails, and only says that that docker run command was the cause, instead of more micro details.

I added basic logging for that command.

~10 lines changes in ventis/controller/cloud_provider_logic/EC2/_runtime.py

Summary by CodeRabbit

  • New Features

    • Added runtime information persistence for controller activity, including execution time, resource usage, workflow, agent, and completion details.
    • Added automatic tracking of request creation and completion timestamps.
    • Added workflow and agent metadata to runtime records.
    • Enabled configurable local SQLite storage for runtime data.
  • Bug Fixes

    • Improved EC2 container image transfer diagnostics and error reporting.
  • Tests

    • Added coverage for runtime data persistence and updates.

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds Redis-to-SQLAlchemy runtime persistence, records future lifecycle metadata, wires persistence into controller polling, configures SQLite storage, adds coverage, and improves EC2 image-transfer diagnostics and ignore rules.

Changes

Runtime persistence

Layer / File(s) Summary
Runtime metadata capture
ventis/future.py, ventis/deploy.py, ventis/controller/local_controller_frontend.py, ventis/controller/local_controller.py
Future creation, workflow, agent, request context, and completion timestamps are recorded in Redis.
Redis-to-SQL persistence
ventis/controller/utils/sqlalchemy.py, tests/test_runtime_sqlalchemy.py, pyproject.toml, requirements.txt
SQLAlchemy engine caching, Redis future extraction, transactional upserts, dependency entries, and SQLite-backed tests are added.
Controller persistence wiring
ventis/controller/global_controller.py, ventis/templates/config/global_controller.yaml
Controller polling sends Redis-derived runtime rows and per-agent resources to the configured database.

EC2 bootstrap diagnostics

Layer / File(s) Summary
EC2 transfer handling
ventis/controller/cloud_provider_logic/EC2/_runtime.py, tests/test_runtime_ec2.py
EC2 image transfer uses Bash pipe failure handling and logs subprocess output; SSH key path test formatting is updated.

Repository hygiene

Layer / File(s) Summary
Ignore rules
.gitignore
Sandbox and selected EC2 end-to-end test paths are ignored.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Future
  participant Redis
  participant GlobalController
  participant SQLAlchemy
  participant RuntimeInformation
  Future->>Redis: Store created_at
  GlobalController->>Redis: Pull future hashes
  GlobalController->>SQLAlchemy: Send rows and resources
  SQLAlchemy->>Redis: Read workflow metadata
  SQLAlchemy->>RuntimeInformation: Upsert runtime_information
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is related to the new deploy-time logging, though it omits the broader database and controller changes in the PR.
Docstring Coverage ✅ Passed Docstring coverage is 91.67% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ventis-build-logs

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ventis/controller/local_controller.py (1)

415-417: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Restore thread-local request context after execution.

Executor threads are reused, but this context is never cleared. A later request lacking request_id can inherit the prior request’s ID, causing nested futures to be persisted under the wrong session. Reset or restore the prior context in a finally block.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ventis/controller/local_controller.py` around lines 415 - 417, Update the
worker-thread flow around ventis_context.set_request_id to capture the prior
request context, apply request_id when present, and restore the previous value
in a finally block after execution. Ensure reused executor threads cannot retain
a request ID when the current request lacks one.
🧹 Nitpick comments (1)
ventis/controller/cloud_provider_logic/EC2/_runtime.py (1)

231-247: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add regression coverage for transfer failures.

The existing bootstrap test exercises only a successful subprocess.run. Add a failure case asserting that the raised error includes captured diagnostics, and verify the pipeline invokes Bash with pipefail.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ventis/controller/cloud_provider_logic/EC2/_runtime.py` around lines 231 -
247, Add regression coverage for the image-transfer failure path around the
subprocess invocation: configure the mocked result with a nonzero return code
and captured stderr, assert the raised RuntimeError includes that diagnostic
text, and verify subprocess.run is called with executable="/bin/bash" so the
pipeline uses pipefail. Preserve the existing successful-transfer test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ventis/controller/cloud_provider_logic/EC2/_runtime.py`:
- Around line 232-241: Update the image-transfer subprocess.run invocation to
enforce a finite timeout, covering both SSH connection and stalled docker
save/load operations. Use the existing command-timeout configuration or an
appropriate bounded value, and preserve the current pipeline, output capture,
and Bash execution behavior.

In `@ventis/controller/global_controller.py`:
- Around line 405-410: Update the send_data call within _poll_controllers to
catch database/persistence exceptions, log the failure, and allow polling to
continue so later polls retry persistence. Keep controller health checks and
routing maintenance running, and do not let the exception propagate through
run().
- Around line 405-410: Update the flow around send_data and pull_data so
completed request records are acknowledged as persisted before asynchronous
cleanup removes their future:* Redis hashes. Add a persistence
acknowledgement/queue, or defer deletion until send_data confirms storage,
ensuring requests completing between polls still produce canonical runtime rows.

In `@ventis/controller/local_controller_frontend.py`:
- Around line 43-45: Update the forwarded-future handling around the Redis hset
and pull_data lifecycle flow so the target controller does not create a partial
future:<id> hash. Keep the source controller’s hash as the single canonical
lifecycle record, and route completion updates back to that owner while
preserving request_id, workflow, and created_at.

In `@ventis/controller/utils/sqlalchemy.py`:
- Around line 11-30: Initialize or migrate the runtime_information table before
the _UPSERT statement can execute, including its columns and future_id conflict
constraint. Integrate this schema setup into the module’s existing database
startup or persistence flow so fresh sqlite:///ventis_runtime.db databases work
without test-only table creation.

---

Outside diff comments:
In `@ventis/controller/local_controller.py`:
- Around line 415-417: Update the worker-thread flow around
ventis_context.set_request_id to capture the prior request context, apply
request_id when present, and restore the previous value in a finally block after
execution. Ensure reused executor threads cannot retain a request ID when the
current request lacks one.

---

Nitpick comments:
In `@ventis/controller/cloud_provider_logic/EC2/_runtime.py`:
- Around line 231-247: Add regression coverage for the image-transfer failure
path around the subprocess invocation: configure the mocked result with a
nonzero return code and captured stderr, assert the raised RuntimeError includes
that diagnostic text, and verify subprocess.run is called with
executable="/bin/bash" so the pipeline uses pipefail. Preserve the existing
successful-transfer test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b2fb95f4-311b-4e43-936d-b4dbd6529d57

📥 Commits

Reviewing files that changed from the base of the PR and between 1aac0d5 and 568c1df.

📒 Files selected for processing (13)
  • .gitignore
  • pyproject.toml
  • requirements.txt
  • tests/test_runtime_ec2.py
  • tests/test_runtime_sqlalchemy.py
  • ventis/controller/cloud_provider_logic/EC2/_runtime.py
  • ventis/controller/global_controller.py
  • ventis/controller/local_controller.py
  • ventis/controller/local_controller_frontend.py
  • ventis/controller/utils/sqlalchemy.py
  • ventis/deploy.py
  • ventis/future.py
  • ventis/templates/config/global_controller.yaml
💤 Files with no reviewable changes (1)
  • .gitignore

Comment on lines 232 to +241
result = subprocess.run(
"set -o pipefail; "
f"docker save {shlex.quote(image)} | ssh -o StrictHostKeyChecking=no "
f"-o IdentitiesOnly=yes -i {shlex.quote(key)} "
f"{shlex.quote(f'{ssh_user}@{host}')} 'sudo docker load'",
shell=True,
capture_output=True,
text=True,
executable="/bin/bash",
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Bound the image-transfer subprocess.

This direct SSH pipeline bypasses global_controller.py:_run_cmd, which supplies ConnectTimeout=10, and subprocess.run has no timeout. An unreachable host or stalled docker load can therefore block EC2 bootstrapping indefinitely.

Proposed fix
         f"docker save {shlex.quote(image)} | ssh -o StrictHostKeyChecking=no "
+        f"-o ConnectTimeout=10 "
         f"-o IdentitiesOnly=yes -i {shlex.quote(key)} "
         f"{shlex.quote(f'{ssh_user}@{host}')} 'sudo docker load'",
...
         executable="/bin/bash",
+        timeout=cfg.get("image_transfer_timeout", 300),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
result = subprocess.run(
"set -o pipefail; "
f"docker save {shlex.quote(image)} | ssh -o StrictHostKeyChecking=no "
f"-o IdentitiesOnly=yes -i {shlex.quote(key)} "
f"{shlex.quote(f'{ssh_user}@{host}')} 'sudo docker load'",
shell=True,
capture_output=True,
text=True,
executable="/bin/bash",
)
result = subprocess.run(
"set -o pipefail; "
f"docker save {shlex.quote(image)} | ssh -o StrictHostKeyChecking=no "
f"-o ConnectTimeout=10 "
f"-o IdentitiesOnly=yes -i {shlex.quote(key)} "
f"{shlex.quote(f'{ssh_user}@{host}')} 'sudo docker load'",
shell=True,
capture_output=True,
text=True,
executable="/bin/bash",
timeout=cfg.get("image_transfer_timeout", 300),
)
🧰 Tools
🪛 OpenGrep (1.25.0)

[ERROR] 232-241: Dynamic command passed to subprocess with shell=True. Use a command list without shell=True, or use shlex.quote() to sanitize input.

(coderabbit.command-injection.python-shell-true)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ventis/controller/cloud_provider_logic/EC2/_runtime.py` around lines 232 -
241, Update the image-transfer subprocess.run invocation to enforce a finite
timeout, covering both SSH connection and stalled docker save/load operations.
Use the existing command-timeout configuration or an appropriate bounded value,
and preserve the current pipeline, output capture, and Bash execution behavior.

Comment on lines +405 to +410
send_data(
pull_data(node_redis),
{c["name"]: c.get("resources", {}) for c in self.controllers},
node_redis,
self.config.get("database", {}).get("url"),
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Do not let database failures stop controller polling.

send_data() exceptions propagate through _poll_controllers() and out of run(), terminating health checks and routing maintenance when the database is unavailable or misconfigured. Isolate persistence failures, log them, and retry on later polls.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ventis/controller/global_controller.py` around lines 405 - 410, Update the
send_data call within _poll_controllers to catch database/persistence
exceptions, log the failure, and allow polling to continue so later polls retry
persistence. Keep controller health checks and routing maintenance running, and
do not let the exception propagate through run().

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Persist before cleanup deletes the Redis source records.

Persistence is periodic, but completed requests are asynchronously cleaned up and their future:* hashes deleted. A request that completes after one poll can be removed before the next, leaving no runtime row. Add a persistence acknowledgement/queue or defer deletion until the canonical records have been stored.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ventis/controller/global_controller.py` around lines 405 - 410, Update the
flow around send_data and pull_data so completed request records are
acknowledged as persisted before asynchronous cleanup removes their future:*
Redis hashes. Add a persistence acknowledgement/queue, or defer deletion until
send_data confirms storage, ensuring requests completing between polls still
produce canonical runtime rows.

Comment on lines +43 to +45
data = json.loads(request.resonse)
future_id = data.get("future_id")
self.redis.hset(f"future:{future_id}", "agent", data.get("service"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Do not persist a partial duplicate for forwarded futures.

The target controller creates future:<id> with only agent. pull_data() still treats it as a row, and its later finished_at write is upserted over the source record for the same future_id. That replacement loses request_id/workflow and uses created_at=0, producing incorrect execution times. Keep lifecycle metadata in one canonical Redis hash, or replicate the complete record and propagate completion back to that owner.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ventis/controller/local_controller_frontend.py` around lines 43 - 45, Update
the forwarded-future handling around the Redis hset and pull_data lifecycle flow
so the target controller does not create a partial future:<id> hash. Keep the
source controller’s hash as the single canonical lifecycle record, and route
completion updates back to that owner while preserving request_id, workflow, and
created_at.

Comment on lines +11 to +30
_UPSERT = text(
"""
INSERT INTO runtime_information (
future_id, session_id, workflow, agent, execution_time,
cpu_resource, gpu_resource, created_at, updated_at
) VALUES (
:future_id, :session_id, :workflow, :agent, :execution_time,
:cpu_resource, :gpu_resource, :created_at, :updated_at
)
ON CONFLICT(future_id) DO UPDATE SET
session_id=excluded.session_id,
workflow=excluded.workflow,
agent=excluded.agent,
execution_time=excluded.execution_time,
cpu_resource=excluded.cpu_resource,
gpu_resource=excluded.gpu_resource,
created_at=excluded.created_at,
updated_at=excluded.updated_at
"""
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Create or migrate runtime_information before issuing UPSERTs.

A fresh sqlite:///ventis_runtime.db has no table, while this module only executes inserts. The test hides this by manually creating the table. Add a migration or startup schema initialization; otherwise the first persisted future raises a database error.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ventis/controller/utils/sqlalchemy.py` around lines 11 - 30, Initialize or
migrate the runtime_information table before the _UPSERT statement can execute,
including its columns and future_id conflict constraint. Integrate this schema
setup into the module’s existing database startup or persistence flow so fresh
sqlite:///ventis_runtime.db databases work without test-only table creation.

@Saaketh0

Copy link
Copy Markdown
Collaborator Author

These changes were made and merged in PR#16

@Saaketh0 Saaketh0 closed this Jul 21, 2026
@Saaketh0
Saaketh0 deleted the ventis-build-logs branch July 21, 2026 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant