Skip to content

Conversation

rescrv
Copy link
Contributor

@rescrv rescrv commented Oct 6, 2025

Description of changes

This PR adds a scheduler that talks to the sysdb to pull tasks.

Test plan

CI

Migration plan

N/A

Observability plan

N/A

Documentation Changes

N/A

Copy link

github-actions bot commented Oct 6, 2025

Reviewer Checklist

Please leverage this checklist to ensure your code review is thorough before approving

Testing, Bugs, Errors, Logs, Documentation

  • Can you think of any use case in which the code does not behave as intended? Have they been tested?
  • Can you think of any inputs or external events that could break the code? Is user input validated and safe? Have they been tested?
  • If appropriate, are there adequate property based tests?
  • If appropriate, are there adequate unit tests?
  • Should any logging, debugging, tracing information be added or removed?
  • Are error messages user-friendly?
  • Have all documentation changes needed been made?
  • Have all non-obvious changes been commented?

System Compatibility

  • Are there any potential impacts on other parts of the system or backward compatibility?
  • Does this change intersect with any items on our roadmap, and if so, is there a plan for fitting them together?

Quality

  • Is this code of a unexpectedly high quality (Readability, Modularity, Intuitiveness)

Copy link
Contributor

propel-code-bot bot commented Oct 6, 2025

Add Heap Scheduler Integration between sysdb and Heap Tender (Task Scheduling Orchestration)

This PR introduces substantial orchestration between the Rust heap scheduling/compaction layer (s3heap-service) and the Go sysdb coordination layer to enable scheduled task execution based on sysdb state. It includes protocol additions (gRPC/protobuf), new sysdb APIs for task scheduling/advancement, and a full Rust integration that pulls, schedules, and acknowledges tasks from sysdb, wiring real scheduler state into HeapTender. Additionally, several tests, database DAO implementations, and minor refactors are included to fully close the end-to-end loop for distributed heap scheduling and durable task progression.

Key Changes

• Introduced AdvanceTask RPC in sysdb: Plumbed through Go protobuf, coordinator, DAO, and gRPC server.
• Added PeekScheduleByCollectionId RPC for batch scheduling lookups based on collection IDs.
• Expanded Go sysdb DAO (taskDb) and interface to support GetByID, AdvanceTask, and PeekScheduleByCollectionId, with new test coverage in task_test.go.
• Integrated sysdb-based scheduling and nonce advancement into the Rust HeapTender orchestration logic-now triggers sysdb peeks, converts schedule entries, and calls HeapWriter.
• Expanded Rust types to support task schedule entries (ScheduleEntry) and conversion from proto to type-safe representations.
• Wire up sysdb config and client into the Rust heap tender service configuration and startup flow; enforce correct sysdb mode (grpc, not sqlite).
• Schema/proto changes: Added/updated messages for AdvanceTask, PeekScheduleByCollectionId, and schedule entry representations.
• Refactored Rust S3heap schedule/triggerable types to be copyable, hashable, and comparable for efficient use in collections and deduplication logic.
• Numerous test updates and additions covering DAO correctness, schedule peeking/filtering, and end-to-end tendering.
• Cargo.toml/lock and workspace dependency updates for new sysdb/chrono dependencies and propagation.

Affected Areas

go/pkg/sysdb/coordinator/task.go (protos/coordination; business logic)
go/pkg/sysdb/metastore/db/dao/task.go and related DAO/test files
idl/chromadb/proto/coordinator.proto (protobuf API surface)
rust/s3heap-service/ (src/lib.rs - HeapTender logic; config; startup)
rust/sysdb/ (sysdb-side proto bindings, error handling, and peeks)
rust/types/ and rust/s3heap/ (task schedule and heap types, S3heap scheduler interface)
rust/s3heap/tests/ and rust/s3heap-service/tests/ (integration and unit tests)
• Cargo.toml and Cargo.lock files (dependency tree)

This summary was automatically generated by @propel-code-bot

Comment on lines 126 to 182
// Can do both calls with a JOIN
task, err := s.catalog.metaDomain.TaskDb(ctx).GetByName(req.InputCollectionId, req.TaskName)
if err != nil {
return nil, err
}

// If task not found, return empty response
if task == nil {
return nil, common.ErrTaskNotFound
}

// Look up operator name from operators table
operator, err := s.catalog.metaDomain.OperatorDb(ctx).GetByID(task.OperatorID)
if err != nil {
log.Error("GetTaskByName: failed to get operator", zap.Error(err))
return nil, err
}
if operator == nil {
log.Error("GetTaskByName: operator not found", zap.String("operator_id", task.OperatorID.String()))
return nil, common.ErrOperatorNotFound
}
Copy link
Contributor

Choose a reason for hiding this comment

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

[PerformanceOptimization]

You've correctly identified a potential optimization with the comment // Can do both calls with a JOIN. To avoid making two separate database calls, you could implement a dedicated DAO method that performs a JOIN between the tasks and operators tables. This would improve efficiency and prevent potential N+1 query issues if this function is called in a loop in the future.

For example, you could add a method like GetByNameWithOperator to your ITaskDb interface:

// In dbmodel/task.go
type TaskAndOperator struct {
    Task
    OperatorName string `gorm:"column:operator_name"`
}

// In ITaskDb interface
GetByNameWithOperator(inputCollectionID string, taskName string) (*TaskAndOperator, error)

// In dao/task.go
func (s *taskDb) GetByNameWithOperator(inputCollectionID string, taskName string) (*dbmodel.TaskAndOperator, error) {
    var result dbmodel.TaskAndOperator
    err := s.db.Table("tasks").
        Select("tasks.*, operators.operator_name").
        Joins("JOIN operators ON tasks.operator_id = operators.operator_id").
        Where("tasks.input_collection_id = ?", inputCollectionID).
        Where("tasks.task_name = ?", taskName).
        Where("tasks.is_deleted = ?", false).
        First(&result).Error

    if err != nil {
        if errors.Is(err, gorm.ErrRecordNotFound) {
            return nil, nil
        }
        return nil, err
    }
    return &result, nil
}

Then GetTaskByName in the coordinator can be simplified to a single database call.

Context for Agents
[**PerformanceOptimization**]

You've correctly identified a potential optimization with the comment `// Can do both calls with a JOIN`. To avoid making two separate database calls, you could implement a dedicated DAO method that performs a JOIN between the `tasks` and `operators` tables. This would improve efficiency and prevent potential N+1 query issues if this function is called in a loop in the future.

For example, you could add a method like `GetByNameWithOperator` to your `ITaskDb` interface:

```go
// In dbmodel/task.go
type TaskAndOperator struct {
    Task
    OperatorName string `gorm:"column:operator_name"`
}

// In ITaskDb interface
GetByNameWithOperator(inputCollectionID string, taskName string) (*TaskAndOperator, error)

// In dao/task.go
func (s *taskDb) GetByNameWithOperator(inputCollectionID string, taskName string) (*dbmodel.TaskAndOperator, error) {
    var result dbmodel.TaskAndOperator
    err := s.db.Table("tasks").
        Select("tasks.*, operators.operator_name").
        Joins("JOIN operators ON tasks.operator_id = operators.operator_id").
        Where("tasks.input_collection_id = ?", inputCollectionID).
        Where("tasks.task_name = ?", taskName).
        Where("tasks.is_deleted = ?", false).
        First(&result).Error

    if err != nil {
        if errors.Is(err, gorm.ErrRecordNotFound) {
            return nil, nil
        }
        return nil, err
    }
    return &result, nil
}
```

Then `GetTaskByName` in the coordinator can be simplified to a single database call.

File: go/pkg/sysdb/coordinator/task.go
Line: 146

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not for this PR.

@rescrv rescrv requested a review from tanujnay112 October 6, 2025 20:45
@rescrv rescrv changed the base branch from main to rescrv/refactor-scheduler October 6, 2025 22:30
Comment on lines 20 to 44
CREATE TABLE "public"."tasks" (
"task_id" uuid NOT NULL,
"task_name" text NOT NULL,
"tenant_id" text NOT NULL,
"database_id" text NOT NULL,
"input_collection_id" text NOT NULL, -- Keeping these as text instead of UUID until collections.id becomes a UUID
"output_collection_name" text NOT NULL,
"operator_id" uuid NOT NULL,
"operator_params" jsonb NOT NULL,
"completion_offset" bigint NOT NULL DEFAULT 0,
"last_run" timestamp NULL DEFAULT NULL,
"next_run" timestamp NULL DEFAULT NULL,
"min_records_for_task" bigint NOT NULL DEFAULT 100,
"current_attempts" integer NOT NULL DEFAULT 0,
"is_alive" boolean NOT NULL DEFAULT true,
"is_deleted" boolean NOT NULL DEFAULT false,
"created_at" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"task_template_parent" uuid NULL,
"next_nonce" UUID NOT NULL, -- UUIDv7
"oldest_written_nonce" UUID DEFAULT NULL, -- UUIDv7
PRIMARY KEY ("task_id"),
CONSTRAINT "unique_task_per_collection" UNIQUE ("input_collection_id", "task_name")
);
Copy link
Contributor

Choose a reason for hiding this comment

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

[BestPractice]

The tasks table defines an operator_id column but lacks a foreign key constraint to the operators table. This could lead to data integrity issues if an operator is deleted, leaving tasks with orphaned operator_id references. This would cause GetTaskByName to fail when it tries to look up the operator.

To ensure referential integrity, please consider adding a foreign key constraint.

Suggested Change
Suggested change
CREATE TABLE "public"."tasks" (
"task_id" uuid NOT NULL,
"task_name" text NOT NULL,
"tenant_id" text NOT NULL,
"database_id" text NOT NULL,
"input_collection_id" text NOT NULL, -- Keeping these as text instead of UUID until collections.id becomes a UUID
"output_collection_name" text NOT NULL,
"operator_id" uuid NOT NULL,
"operator_params" jsonb NOT NULL,
"completion_offset" bigint NOT NULL DEFAULT 0,
"last_run" timestamp NULL DEFAULT NULL,
"next_run" timestamp NULL DEFAULT NULL,
"min_records_for_task" bigint NOT NULL DEFAULT 100,
"current_attempts" integer NOT NULL DEFAULT 0,
"is_alive" boolean NOT NULL DEFAULT true,
"is_deleted" boolean NOT NULL DEFAULT false,
"created_at" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"task_template_parent" uuid NULL,
"next_nonce" UUID NOT NULL, -- UUIDv7
"oldest_written_nonce" UUID DEFAULT NULL, -- UUIDv7
PRIMARY KEY ("task_id"),
CONSTRAINT "unique_task_per_collection" UNIQUE ("input_collection_id", "task_name")
);
CREATE TABLE "public"."tasks" (
"task_id" uuid NOT NULL,
"task_name" text NOT NULL,
"tenant_id" text NOT NULL,
"database_id" text NOT NULL,
"input_collection_id" text NOT NULL, -- Keeping these as text instead of UUID until collections.id becomes a UUID
"output_collection_name" text NOT NULL,
"operator_id" uuid NOT NULL,
"operator_params" jsonb NOT NULL,
"completion_offset" bigint NOT NULL DEFAULT 0,
"last_run" timestamp NULL DEFAULT NULL,
"next_run" timestamp NULL DEFAULT NULL,
"min_records_for_task" bigint NOT NULL DEFAULT 100,
"current_attempts" integer NOT NULL DEFAULT 0,
"is_alive" boolean NOT NULL DEFAULT true,
"is_deleted" boolean NOT NULL DEFAULT false,
"created_at" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
"task_template_parent" uuid NULL,
"next_nonce" UUID NOT NULL, -- UUIDv7
"oldest_written_nonce" UUID DEFAULT NULL, -- UUIDv7
PRIMARY KEY ("task_id"),
CONSTRAINT "unique_task_per_collection" UNIQUE ("input_collection_id", "task_name"),
CONSTRAINT "fk_tasks_operator_id" FOREIGN KEY ("operator_id") REFERENCES "public"."operators" ("operator_id")
);

Committable suggestion

Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Context for Agents
[**BestPractice**]

The `tasks` table defines an `operator_id` column but lacks a foreign key constraint to the `operators` table. This could lead to data integrity issues if an operator is deleted, leaving tasks with orphaned `operator_id` references. This would cause `GetTaskByName` to fail when it tries to look up the operator.

To ensure referential integrity, please consider adding a foreign key constraint.

<details>
<summary>Suggested Change</summary>

```suggestion
CREATE TABLE "public"."tasks" (
  "task_id" uuid NOT NULL,
  "task_name" text NOT NULL,
  "tenant_id" text NOT NULL,
  "database_id" text NOT NULL,
  "input_collection_id" text NOT NULL, -- Keeping these as text instead of UUID until collections.id becomes a UUID
  "output_collection_name" text NOT NULL,
  "operator_id" uuid NOT NULL,
  "operator_params" jsonb NOT NULL,
  "completion_offset" bigint NOT NULL DEFAULT 0,
  "last_run" timestamp NULL DEFAULT NULL,
  "next_run" timestamp NULL DEFAULT NULL,
  "min_records_for_task" bigint NOT NULL DEFAULT 100,
  "current_attempts" integer NOT NULL DEFAULT 0,
  "is_alive" boolean NOT NULL DEFAULT true,
  "is_deleted" boolean NOT NULL DEFAULT false,
  "created_at" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  "updated_at" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  "task_template_parent" uuid NULL,
  "next_nonce" UUID NOT NULL, -- UUIDv7
  "oldest_written_nonce" UUID DEFAULT NULL, -- UUIDv7
  PRIMARY KEY ("task_id"),
  CONSTRAINT "unique_task_per_collection" UNIQUE ("input_collection_id", "task_name"),
  CONSTRAINT "fk_tasks_operator_id" FOREIGN KEY ("operator_id") REFERENCES "public"."operators" ("operator_id")
);
```

⚡ **Committable suggestion**

Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

</details>

File: go/pkg/sysdb/metastore/db/migrations/20251001073000.sql
Line: 43

@rescrv rescrv force-pushed the rescrv/refactor-scheduler branch from e8da43e to f96c1d8 Compare October 7, 2025 15:56
@rescrv rescrv force-pushed the rescrv/heap-scheduler branch from 5e54c6d to 52da7a6 Compare October 7, 2025 16:19
@rescrv rescrv force-pushed the rescrv/heap-scheduler branch from 52da7a6 to 43edec4 Compare October 7, 2025 17:42
Comment on lines 135 to 148
fn camel_to_snake_case(s: &str) -> String {
let mut result = String::new();
for (i, ch) in s.chars().enumerate() {
if ch.is_uppercase() {
if i > 0 {
result.push('_');
}
result.push(ch.to_ascii_lowercase());
} else {
result.push(ch);
}
}
result
}
Copy link
Contributor

Choose a reason for hiding this comment

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

[BestPractice]

The current implementation of camel_to_snake_case incorrectly handles acronyms in Go constant names. For example, a name like HTTPGetter would be converted to h_t_t_p_getter instead of the correct http_getter. While this works for the current RecordCounter constant, it will cause issues with future constants that use acronyms.

A more robust implementation should handle consecutive uppercase letters correctly.

Suggested Change
Suggested change
fn camel_to_snake_case(s: &str) -> String {
let mut result = String::new();
for (i, ch) in s.chars().enumerate() {
if ch.is_uppercase() {
if i > 0 {
result.push('_');
}
result.push(ch.to_ascii_lowercase());
} else {
result.push(ch);
}
}
result
}
fn camel_to_snake_case(s: &str) -> String {
let mut result = String::new();
let mut last_was_upper = false;
for (i, ch) in s.chars().enumerate() {
if ch.is_uppercase() {
if i > 0 && !last_was_upper {
result.push('_');
}
result.push(ch.to_ascii_lowercase());
last_was_upper = true;
} else {
result.push(ch);
last_was_upper = false;
}
}
result
}

Committable suggestion

Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Context for Agents
[**BestPractice**]

The current implementation of `camel_to_snake_case` incorrectly handles acronyms in Go constant names. For example, a name like `HTTPGetter` would be converted to `h_t_t_p_getter` instead of the correct `http_getter`. While this works for the current `RecordCounter` constant, it will cause issues with future constants that use acronyms.

A more robust implementation should handle consecutive uppercase letters correctly.
<details>
<summary>Suggested Change</summary>

```suggestion
fn camel_to_snake_case(s: &str) -> String {
    let mut result = String::new();
    let mut last_was_upper = false;
    for (i, ch) in s.chars().enumerate() {
        if ch.is_uppercase() {
            if i > 0 && !last_was_upper {
                result.push('_');
            }
            result.push(ch.to_ascii_lowercase());
            last_was_upper = true;
        } else {
            result.push(ch);
            last_was_upper = false;
        }
    }
    result
}
```

⚡ **Committable suggestion**

Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

</details>

File: rust/types/operator_codegen.rs
Line: 148

Base automatically changed from rescrv/refactor-scheduler to main October 7, 2025 21:30
@rescrv rescrv force-pushed the rescrv/heap-scheduler branch from 43edec4 to 4007de1 Compare October 7, 2025 21:41
Comment on lines +279 to +281
chroma_sysdb::SysDbConfig::Grpc(_) => {}
chroma_sysdb::SysDbConfig::Sqlite(_) => {
panic!("Expected grpc sysdb config, got sqlite sysdb config")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

[BestPractice]

Using panic! for configuration errors can cause the service to crash abruptly on startup, which can be difficult to debug in production environments. Since this function already returns a Result, it would be more robust to return an Err variant for invalid configurations. This allows for graceful error handling and clearer error messages upon service startup failure.

Context for Agents
[**BestPractice**]

Using `panic!` for configuration errors can cause the service to crash abruptly on startup, which can be difficult to debug in production environments. Since this function already returns a `Result`, it would be more robust to return an `Err` variant for invalid configurations. This allows for graceful error handling and clearer error messages upon service startup failure.

File: rust/s3heap-service/src/lib.rs
Line: 282

@blacksmith-sh blacksmith-sh bot deleted a comment from rescrv Oct 7, 2025
@rescrv rescrv force-pushed the rescrv/heap-scheduler branch from 4007de1 to 08647ab Compare October 8, 2025 15:37
}

// Mark a task run as complete and set the nonce for the next task run.
func (s *Coordinator) DoneTask(ctx context.Context, req *coordinatorpb.DoneTaskRequest) (*coordinatorpb.DoneTaskResponse, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we put a verb in this method's name to make it clear that this modifies state?

Comment on lines +315 to +343
func (suite *TaskDbTestSuite) TestTaskDb_GetByID() {
taskID := uuid.New()
operatorID := dbmodel.OperatorRecordCounter
nextNonce, _ := uuid.NewV7()

task := &dbmodel.Task{
ID: taskID,
Name: "test-get-by-id-task",
OperatorID: operatorID,
InputCollectionID: "input_col_id",
OutputCollectionName: "output_col_name",
OperatorParams: "{}",
TenantID: "tenant1",
DatabaseID: "db1",
MinRecordsForTask: 100,
NextNonce: nextNonce,
}

err := suite.Db.Insert(task)
suite.Require().NoError(err)

retrieved, err := suite.Db.GetByID(taskID)
suite.Require().NoError(err)
suite.Require().NotNil(retrieved)
suite.Require().Equal(task.ID, retrieved.ID)
suite.Require().Equal(task.Name, retrieved.Name)
suite.Require().Equal(task.OperatorID, retrieved.OperatorID)

suite.db.Unscoped().Delete(&dbmodel.Task{}, "task_id = ?", task.ID)
Copy link
Contributor

Choose a reason for hiding this comment

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

[BestPractice]

Resource leak: The test creates and inserts a task but uses Unscoped().Delete() for cleanup, which bypasses GORM hooks and constraints. If the test fails before reaching cleanup, the task will remain in the database permanently. Use proper cleanup with defer or t.Cleanup():

func (suite *TaskDbTestSuite) TestTaskDb_GetByID() {
    // ... setup code ...
    
    // Clean up immediately after insert, regardless of test outcome
    suite.T().Cleanup(func() {
        suite.db.Unscoped().Delete(&dbmodel.Task{}, "task_id = ?", task.ID)
    })
    
    err := suite.Db.Insert(task)
    suite.Require().NoError(err)
    // ... rest of test ...
}
Context for Agents
[**BestPractice**]

Resource leak: The test creates and inserts a task but uses `Unscoped().Delete()` for cleanup, which bypasses GORM hooks and constraints. If the test fails before reaching cleanup, the task will remain in the database permanently. Use proper cleanup with `defer` or `t.Cleanup()`:

```go
func (suite *TaskDbTestSuite) TestTaskDb_GetByID() {
    // ... setup code ...
    
    // Clean up immediately after insert, regardless of test outcome
    suite.T().Cleanup(func() {
        suite.db.Unscoped().Delete(&dbmodel.Task{}, "task_id = ?", task.ID)
    })
    
    err := suite.Db.Insert(task)
    suite.Require().NoError(err)
    // ... rest of test ...
}
```

File: go/pkg/sysdb/metastore/db/dao/task_test.go
Line: 343

return &task, nil
}

func (s *taskDb) FinishTask(taskID uuid.UUID, taskRunNonce uuid.UUID) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we consider generating the next nonce here instead of letting the caller supply it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is that not what the code is doing?


task := &dbmodel.Task{
ID: taskID,
Name: "test-done-task",
Copy link
Contributor

Choose a reason for hiding this comment

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

Naming inconsistency with FinishTask

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated.


task := &dbmodel.Task{
ID: taskID,
Name: "test-done-task-wrong-nonce",
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ditto.

Comment on lines 50 to 54
reader: LogReader,
cursor: CursorStore,
_writer: HeapWriter,
writer: HeapWriter,
}

Copy link
Contributor

Choose a reason for hiding this comment

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

[BestPractice]

Missing error handling: If self.sysdb.peek_schedule_by_collection_id() fails, the method returns early with ? but doesn't log the failure or provide context about which collections caused the issue. This makes debugging production failures difficult. Add error logging:

let scheduled = self
    .sysdb
    .clone()
    .peek_schedule_by_collection_id(&collection_ids)
    .await
    .map_err(|e| {
        log::error!("Failed to peek schedule for collections {:?}: {}", collection_ids, e);
        e
    })?;
Context for Agents
[**BestPractice**]

Missing error handling: If `self.sysdb.peek_schedule_by_collection_id()` fails, the method returns early with `?` but doesn't log the failure or provide context about which collections caused the issue. This makes debugging production failures difficult. Add error logging:

```rust
let scheduled = self
    .sysdb
    .clone()
    .peek_schedule_by_collection_id(&collection_ids)
    .await
    .map_err(|e| {
        log::error!("Failed to peek schedule for collections {:?}: {}", collection_ids, e);
        e
    })?;
```

File: rust/s3heap-service/src/lib.rs
Line: 54

@blacksmith-sh blacksmith-sh bot deleted a comment from rescrv Oct 14, 2025
@rescrv rescrv force-pushed the rescrv/heap-scheduler branch from 2741ea7 to 75ff5ab Compare October 14, 2025 21:59
@rescrv rescrv requested a review from tanujnay112 October 14, 2025 22:22
@blacksmith-sh blacksmith-sh bot deleted a comment from rescrv Oct 14, 2025
@rescrv rescrv force-pushed the rescrv/heap-scheduler branch from 75ff5ab to 1de60cc Compare October 14, 2025 23:09
return &task, nil
}

func (s *taskDb) AdvanceTask(taskID uuid.UUID, taskRunNonce uuid.UUID) error {
Copy link
Contributor

Choose a reason for hiding this comment

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

FYI I'm going to remove/modify this later. The path that updates next_nonce also needs to transactionally update completion_offset.

@blacksmith-sh blacksmith-sh bot deleted a comment from rescrv Oct 15, 2025
@rescrv rescrv merged commit cb190f1 into main Oct 15, 2025
113 of 117 checks passed
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.

2 participants