Skip to content

Conversation

@Bencheng21
Copy link
Contributor

@Bencheng21 Bencheng21 commented Dec 12, 2025

implemented listing events handler in baton-sdk.

Summary by CodeRabbit

  • New Features

    • Added listing of event feeds.
    • Added listing of events with pagination, optional start timestamp, cursor support, and annotations support.
  • Chores

    • Added comprehensive payload validation for the new task variants with structured validation errors and multi-error aggregation.
    • Integrated new handlers into task processing so the new task types are recognized, processed, and finished with proper error reporting.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 12, 2025

Walkthrough

Adds two new Task oneof variants (ListEventFeeds, ListEvents) with proto messages, generated validation for those messages, task routing updates, and two c1api handlers that call ConnectorClient and finish tasks (ListEvents supports paginated fetching).

Changes

Cohort / File(s) Summary
Protocol Buffer
proto/c1/connectorapi/baton/v1/baton.proto
Added ListEventsTask and ListEventFeedsTask messages and oneof branches (list_event_feeds = 121, list_events = 122) and new fields (e.g., annotations, start_at, event_feed_id, page_size).
Generated Validation
pb/c1/connectorapi/baton/v1/baton.pb.validate.go
Generated validation for Task_ListEventsTask and Task_ListEventFeedsTask: Validate, ValidateAll, internal validate(all bool), MultiError slice types, ValidationError types, aggregation of nested/annotation errors, and typed-nil handling.
Task Manager Routing
pkg/tasks/c1api/manager.go
Added cases mapping ListEventFeedsType and ListEventsType to NewListEventFeedsHandler and NewListEventsHandler in the Process switch.
Handlers (c1api)
pkg/tasks/c1api/list_event_feeds.go, pkg/tasks/c1api/list_events.go
New handlers and constructors (NewListEventFeedsHandler, NewListEventsHandler): payload extraction/validation, calls to ConnectorClient.ListEventFeeds / ConnectorClient.ListEvents, response construction, pagination handling for ListEvents, and finalization via FinishTask with annotations.
Task Type Mapping
pkg/tasks/tasks.go
Added recognition for v1.Task_ListEventFeeds_case and v1.Task_ListEvents_case in Is and GetType, returning the new task types.
Misc Proto Formatting
proto/c1/connector/v2/...
Minor whitespace/formatting edits: trailing newline and removed empty line in unrelated proto files (no semantic changes).

Sequence Diagram

sequenceDiagram
    participant Manager as c1ApiTaskManager
    participant Handler as ListEventsHandler / ListEventFeedsHandler
    participant Connector as ConnectorClient
    participant Helpers as TaskHelpers

    Manager->>Handler: Dispatch task (ListEventsType / ListEventFeedsType)
    Handler->>Handler: Extract payload & Validate()
    alt validation fails
        Handler->>Helpers: FinishTask(error, non-retryable)
    else validation succeeds
        opt ListEvents pagination
            loop while hasMore
                Handler->>Connector: ListEvents(request{event_feed_id, start_at, page_size, cursor})
                Connector-->>Handler: ListEventsResponse{events, cursor, has_more, annotations}
                Handler->>Handler: Accumulate events, update cursor
            end
        end
        Handler->>Helpers: FinishTask(response, annotations)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I hopped through proto, validate, and span,
I fetched event feeds as fast as I can.
Pages I gather, annotations in tow,
I finish the task and away I go.
🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main feature: support for listing events. It directly corresponds to the primary changes across multiple files (new ListEventsTask, ListEventFeedsTask handlers, and related validation code).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
pb/c1/connectorapi/baton/v1/baton.pb.validate.go (1)

3586-3587: Avoid manual edits in generated validation files; add rules in the .proto instead.
Since this file is generated, the comment will be overwritten on regeneration; if event_feed_id needs constraints, add (validate.rules) to EventFeedTask.event_feed_id in proto/c1/connectorapi/baton/v1/baton.proto and re-generate.

pkg/tasks/c1api/event_feed.go (1)

40-66: Add a safety bound for unbounded event aggregation (large feeds can OOM).
If event_feed_id can produce large histories, aggregating all events into a single []*v2.Event can spike memory. Consider enforcing a max pages/events limit (and returning a non-retryable “response too large” error) or implementing chunked responses if the protocol allows.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bdd80cf and bd3cf85.

⛔ Files ignored due to path filters (2)
  • pb/c1/connectorapi/baton/v1/baton.pb.go is excluded by !**/*.pb.go
  • pb/c1/connectorapi/baton/v1/baton_protoopaque.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (4)
  • pb/c1/connectorapi/baton/v1/baton.pb.validate.go (1 hunks)
  • pkg/tasks/c1api/event_feed.go (1 hunks)
  • pkg/tasks/c1api/manager.go (1 hunks)
  • proto/c1/connectorapi/baton/v1/baton.proto (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/tasks/c1api/manager.go (2)
pkg/types/tasks/tasks.go (1)
  • ListEventsType (96-96)
pkg/tasks/c1api/event_feed.go (1)
  • NewEventFeedHandler (68-73)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: go-test (1.25.2, ubuntu-latest)
  • GitHub Check: go-test (1.25.2, windows-latest)
🔇 Additional comments (2)
pkg/tasks/c1api/manager.go (1)

288-289: Task routing for ListEventsType looks correct.

pkg/tasks/c1api/event_feed.go (1)

68-73: Constructor looks fine.

Comment on lines 27 to 66
func (c *eventFeedHandler) HandleTask(ctx context.Context) error {
ctx, span := tracer.Start(ctx, "eventFeedHandler.HandleTask")
defer span.End()

l := ctxzap.Extract(ctx)
cc := c.helpers.ConnectorClient()

t := c.task.GetEventFeed()
if t == nil {
l.Error("get event feed task was nil", zap.Any("get_event_feed_task", t))
return c.helpers.FinishTask(ctx, nil, nil, errors.Join(errors.New("malformed get event feed task"), ErrTaskNonRetryable))
}

var (
pageToken = ""
events []*v2.Event
)

for {
feeds, err := cc.ListEvents(ctx, v2.ListEventsRequest_builder{
EventFeedId: t.GetEventFeedId(),
StartAt: t.GetStartAt(),
Cursor: pageToken,
}.Build())
if err != nil {
return err
}

events = append(events, feeds.GetEvents()...)
pageToken = feeds.GetCursor()
if !feeds.GetHasMore() {
break
}
}

resp := v2.ListEventsResponse_builder{
Events: events,
}.Build()
return c.helpers.FinishTask(ctx, resp, resp.GetAnnotations(), nil)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: HandleTask must finish the task on ListEvents errors (don’t just return err).
Right now, if cc.ListEvents(...) fails, the handler exits without calling FinishTask, which can leave the task un-finalized despite the manager expecting handlers to finalize.

 func (c *eventFeedHandler) HandleTask(ctx context.Context) error {
 	ctx, span := tracer.Start(ctx, "eventFeedHandler.HandleTask")
 	defer span.End()
@@
 	for {
 		feeds, err := cc.ListEvents(ctx, v2.ListEventsRequest_builder{
 			EventFeedId: t.GetEventFeedId(),
 			StartAt:     t.GetStartAt(),
 			Cursor:      pageToken,
 		}.Build())
 		if err != nil {
-			return err
+			// Ensure the task is finalized on failure.
+			finishErr := c.helpers.FinishTask(ctx, nil, nil, err)
+			if finishErr != nil {
+				return errors.Join(err, finishErr)
+			}
+			// Task is finished; let processing continue.
+			return nil
 		}
 
 		events = append(events, feeds.GetEvents()...)
+		prevToken := pageToken
 		pageToken = feeds.GetCursor()
 		if !feeds.GetHasMore() {
 			break
 		}
+		if pageToken == "" || pageToken == prevToken {
+			err := errors.New("pagination cursor did not advance")
+			finishErr := c.helpers.FinishTask(ctx, nil, nil, err)
+			if finishErr != nil {
+				return errors.Join(err, finishErr)
+			}
+			return nil
+		}
 	}
📝 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
func (c *eventFeedHandler) HandleTask(ctx context.Context) error {
ctx, span := tracer.Start(ctx, "eventFeedHandler.HandleTask")
defer span.End()
l := ctxzap.Extract(ctx)
cc := c.helpers.ConnectorClient()
t := c.task.GetEventFeed()
if t == nil {
l.Error("get event feed task was nil", zap.Any("get_event_feed_task", t))
return c.helpers.FinishTask(ctx, nil, nil, errors.Join(errors.New("malformed get event feed task"), ErrTaskNonRetryable))
}
var (
pageToken = ""
events []*v2.Event
)
for {
feeds, err := cc.ListEvents(ctx, v2.ListEventsRequest_builder{
EventFeedId: t.GetEventFeedId(),
StartAt: t.GetStartAt(),
Cursor: pageToken,
}.Build())
if err != nil {
return err
}
events = append(events, feeds.GetEvents()...)
pageToken = feeds.GetCursor()
if !feeds.GetHasMore() {
break
}
}
resp := v2.ListEventsResponse_builder{
Events: events,
}.Build()
return c.helpers.FinishTask(ctx, resp, resp.GetAnnotations(), nil)
}
func (c *eventFeedHandler) HandleTask(ctx context.Context) error {
ctx, span := tracer.Start(ctx, "eventFeedHandler.HandleTask")
defer span.End()
l := ctxzap.Extract(ctx)
cc := c.helpers.ConnectorClient()
t := c.task.GetEventFeed()
if t == nil {
l.Error("get event feed task was nil", zap.Any("get_event_feed_task", t))
return c.helpers.FinishTask(ctx, nil, nil, errors.Join(errors.New("malformed get event feed task"), ErrTaskNonRetryable))
}
var (
pageToken = ""
events []*v2.Event
)
for {
feeds, err := cc.ListEvents(ctx, v2.ListEventsRequest_builder{
EventFeedId: t.GetEventFeedId(),
StartAt: t.GetStartAt(),
Cursor: pageToken,
}.Build())
if err != nil {
// Ensure the task is finalized on failure.
finishErr := c.helpers.FinishTask(ctx, nil, nil, err)
if finishErr != nil {
return errors.Join(err, finishErr)
}
// Task is finished; let processing continue.
return nil
}
events = append(events, feeds.GetEvents()...)
prevToken := pageToken
pageToken = feeds.GetCursor()
if !feeds.GetHasMore() {
break
}
if pageToken == "" || pageToken == prevToken {
err := errors.New("pagination cursor did not advance")
finishErr := c.helpers.FinishTask(ctx, nil, nil, err)
if finishErr != nil {
return errors.Join(err, finishErr)
}
return nil
}
}
resp := v2.ListEventsResponse_builder{
Events: events,
}.Build()
return c.helpers.FinishTask(ctx, resp, resp.GetAnnotations(), nil)
}
🤖 Prompt for AI Agents
In pkg/tasks/c1api/event_feed.go around lines 27 to 66, the loop returns the raw
error when cc.ListEvents(...) fails which skips calling FinishTask; change the
error branch to call c.helpers.FinishTask to finalize the task before returning.
Replace the current "return err" with code that logs the ListEvents error, calls
c.helpers.FinishTask(ctx, nil, nil, errors.Join(err, ErrTaskNonRetryable)) (or
otherwise wrap the list error consistently with other failures), and then
returns the FinishTask error (or the original error if FinishTask succeeded) so
the task is always finalized on ListEvents failures.

Comment on lines 54 to 74
message EventFeedTask {
repeated google.protobuf.Any annotations = 1;
google.protobuf.Timestamp start_at = 2;
string event_feed_id = 3;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Clarify/validate event_feed_id (required vs optional) to avoid empty-ID semantics.
If event_feed_id is required for correct ListEvents behavior, add a validation rule (e.g., min_len: 1) or make it explicitly required; otherwise, document what an empty string means for connectors/backends.

🤖 Prompt for AI Agents
proto/c1/connectorapi/baton/v1/baton.proto lines 54-58: the field event_feed_id
is currently an unconstrained string which can be empty and cause ambiguous
ListEvents semantics; either make it explicitly required/mandatory or add a
validation rule such as (validate.rules).string.min_len = 1 to enforce non-empty
IDs, and update the proto comment/docs to state the semantics of an empty string
if you intentionally allow it; after changing the proto, regenerate stubs and
update any ListEvents handling to assume non-empty IDs (or explicitly handle the
empty-ID case) and add tests that cover validation and API behavior.

@Bencheng21 Bencheng21 force-pushed the DUCT13790-listing_events branch 2 times, most recently from 8c53267 to 7465e00 Compare December 15, 2025 20:35
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
proto/c1/connectorapi/baton/v1/baton.proto (1)

60-65: Clarify and/or validate event_feed_id / page_size semantics in ListEventsTask.

ListEventsTask currently leaves event_feed_id and page_size unconstrained. That’s OK if:

  • empty event_feed_id is a valid “all feeds” sentinel; and
  • page_size == 0 or very large values are intentionally delegated to the backend.

If instead event_feed_id must be non‑empty or page_size should be within a bounded range, please add PGV rules on these fields (e.g. min_len: 1, or min/max for page_size) and regenerate validation, and document the intended empty/zero semantics. This was already raised in an earlier review and still appears open.

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e7e988d and cda0dde.

⛔ Files ignored due to path filters (2)
  • pb/c1/connectorapi/baton/v1/baton.pb.go is excluded by !**/*.pb.go
  • pb/c1/connectorapi/baton/v1/baton_protoopaque.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (5)
  • pb/c1/connectorapi/baton/v1/baton.pb.validate.go (2 hunks)
  • pkg/tasks/c1api/list_event_feeds.go (1 hunks)
  • pkg/tasks/c1api/list_events.go (1 hunks)
  • pkg/tasks/c1api/manager.go (1 hunks)
  • proto/c1/connectorapi/baton/v1/baton.proto (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
pkg/tasks/c1api/list_event_feeds.go (4)
pkg/types/types.go (1)
  • ConnectorClient (30-46)
pkg/annotations/annotations.go (1)
  • Annotations (12-12)
pb/c1/connectorapi/baton/v1/baton.pb.go (2)
  • Task (82-115)
  • Task (128-128)
pkg/tasks/c1api/manager.go (1)
  • ErrTaskNonRetryable (43-43)
pkg/tasks/c1api/list_events.go (5)
pkg/types/types.go (1)
  • ConnectorClient (30-46)
pkg/annotations/annotations.go (1)
  • Annotations (12-12)
pb/c1/connectorapi/baton/v1/baton_protoopaque.pb.go (2)
  • Task (82-90)
  • Task (103-103)
pb/c1/connectorapi/baton/v1/baton.pb.go (2)
  • Task (82-115)
  • Task (128-128)
pkg/tasks/c1api/manager.go (1)
  • ErrTaskNonRetryable (43-43)
pkg/tasks/c1api/manager.go (3)
pkg/types/tasks/tasks.go (2)
  • ListEventFeedsType (97-97)
  • ListEventsType (96-96)
pkg/tasks/c1api/list_event_feeds.go (1)
  • NewListEventFeedsHandler (51-56)
pkg/tasks/c1api/list_events.go (1)
  • NewListEventsHandler (69-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: go-test (1.25.2, windows-latest)
🔇 Additional comments (3)
proto/c1/connectorapi/baton/v1/baton.proto (1)

55-69: Event feed & listing task modeling looks consistent and backwards‑compatible.

The new EventFeedTask, ListEventsTask, and ListEventFeedsTask messages and their addition to the Task.task_type oneof with tags 121 and 122 follow the existing pattern and avoid field‑number conflicts. No issues from a wire‑compatibility perspective.

Also applies to: 189-190

pkg/tasks/c1api/manager.go (1)

289-292: Handler wiring for new event tasks matches existing pattern.

Dispatching ListEventFeedsType to NewListEventFeedsHandler and ListEventsType to NewListEventsHandler using the existing taskHelpers struct is consistent with other task types; no issues here.

pb/c1/connectorapi/baton/v1/baton.pb.validate.go (1)

927-1007: Generated validation for ListEvents/ListEventFeeds tasks matches proto patterns.

The new Task switch branches for Task_ListEventFeeds and Task_ListEvents, plus the Task_ListEventsTask / Task_ListEventFeedsTask validation scaffolding, are consistent with the existing PGV‑generated patterns for other task messages. Any future tightening of event_feed_id or page_size constraints should be done in the .proto and this file regenerated, rather than edited manually.

Also applies to: 3782-4085

Comment on lines 27 to 49
func (c *listEventFeedsHandler) HandleTask(ctx context.Context) error {
ctx, span := tracer.Start(ctx, "listEventFeedsHandler.HandleTask")
defer span.End()

l := ctxzap.Extract(ctx)
cc := c.helpers.ConnectorClient()

t := c.task.GetEventFeed()
if t == nil {
l.Error("get list event feeds task was nil", zap.Any("get_list_event_feeds_task", t))
return c.helpers.FinishTask(ctx, nil, nil, errors.Join(errors.New("malformed get list event feeds task"), ErrTaskNonRetryable))
}

feeds, err := cc.ListEventFeeds(ctx, &v2.ListEventFeedsRequest{})
if err != nil {
return err
}

resp := v2.ListEventFeedsResponse_builder{
List: feeds.GetList(),
}.Build()
return c.helpers.FinishTask(ctx, resp, resp.GetAnnotations(), nil)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix incorrect getter (GetEventFeed vs GetListEventFeeds) and finish tasks on RPC error.

Two issues here:

  1. Wrong task accessor:

    For ListEventFeedsType tasks, the proto defines a ListEventFeedsTask branch, so the generated accessor on v1.Task will be GetListEventFeeds(). Using GetEventFeed() will return nil for those tasks, causing all valid ListEventFeeds tasks to be marked as “malformed” and finished non‑retryably.

    Suggested change:

  • t := c.task.GetEventFeed()
  • t := c.task.GetListEventFeeds()
    if t == nil {
  •   l.Error("get list event feeds task was nil", zap.Any("get_list_event_feeds_task", t))
    
  •   return c.helpers.FinishTask(ctx, nil, nil, errors.Join(errors.New("malformed get list event feeds task"), ErrTaskNonRetryable))
    
  •   l.Error("list event feeds task was nil", zap.Any("list_event_feeds_task", t))
    
  •   return c.helpers.FinishTask(ctx, nil, nil, errors.Join(errors.New("malformed list event feeds task"), ErrTaskNonRetryable))
    
    }
    
    
  1. ListEventFeeds RPC error path doesn’t call FinishTask:

    As with list_events.go, cc.ListEventFeeds errors currently just return err, which likely leaves the task unfinished. Consider:

  • feeds, err := cc.ListEventFeeds(ctx, &v2.ListEventFeedsRequest{})
  • if err != nil {
  •   return err
    
  • }
  • feeds, err := cc.ListEventFeeds(ctx, &v2.ListEventFeedsRequest{})
  • if err != nil {
  •   return c.helpers.FinishTask(ctx, nil, nil, err)
    
  • }

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **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.

```suggestion
func (c *listEventFeedsHandler) HandleTask(ctx context.Context) error {
 ctx, span := tracer.Start(ctx, "listEventFeedsHandler.HandleTask")
 defer span.End()

 l := ctxzap.Extract(ctx)
 cc := c.helpers.ConnectorClient()

 t := c.task.GetListEventFeeds()
 if t == nil {
 	l.Error("list event feeds task was nil", zap.Any("list_event_feeds_task", t))
 	return c.helpers.FinishTask(ctx, nil, nil, errors.Join(errors.New("malformed list event feeds task"), ErrTaskNonRetryable))
 }

 feeds, err := cc.ListEventFeeds(ctx, &v2.ListEventFeedsRequest{})
 if err != nil {
 	return c.helpers.FinishTask(ctx, nil, nil, err)
 }

 resp := v2.ListEventFeedsResponse_builder{
 	List: feeds.GetList(),
 }.Build()
 return c.helpers.FinishTask(ctx, resp, resp.GetAnnotations(), nil)
}
🤖 Prompt for AI Agents
In pkg/tasks/c1api/list_event_feeds.go around lines 27-49, replace the incorrect
task accessor GetEventFeed() with GetListEventFeeds() so valid ListEventFeeds
tasks are recognized, and change the RPC error path for cc.ListEventFeeds to
finish the task via c.helpers.FinishTask(ctx, nil, nil, err) (and return that)
instead of simply returning the error to ensure the task is completed when the
RPC fails.

Comment on lines 27 to 56
func (c *listEventsHandler) HandleTask(ctx context.Context) error {
ctx, span := tracer.Start(ctx, "listEventHandler.HandleTask")
defer span.End()

l := ctxzap.Extract(ctx)
cc := c.helpers.ConnectorClient()

t := c.task.GetListEvents()
if t == nil {
l.Error("get list event task was nil", zap.Any("get_list_event_task", t))
return c.helpers.FinishTask(ctx, nil, nil, errors.Join(errors.New("malformed get list event task"), ErrTaskNonRetryable))
}

var (
pageToken = ""
events []*v2.Event
)

for {
feeds, err := cc.ListEvents(ctx, v2.ListEventsRequest_builder{
EventFeedId: t.GetEventFeedId(),
StartAt: t.GetStartAt(),
Cursor: pageToken,
PageSize: t.GetPageSize(),
}.Build())
if err != nil {
return err
}

events = append(events, feeds.GetEvents()...)
pageToken = feeds.GetCursor()
if !feeds.GetHasMore() {
break
}
}

resp := v2.ListEventsResponse_builder{
Events: events,
}.Build()
return c.helpers.FinishTask(ctx, resp, resp.GetAnnotations(), nil)
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, find similar handler files in the same directory
find pkg/tasks/c1api -name "*handler*" -o -name "*list_*.go" | head -20

Repository: ConductorOne/baton-sdk

Length of output: 171


🏁 Script executed:

# Check the actual file to confirm the exact code and span name
cat -n pkg/tasks/c1api/list_events.go | head -70

Repository: ConductorOne/baton-sdk

Length of output: 2357


🏁 Script executed:

# Search for other handlers in the codebase to understand FinishTask patterns
rg -A 5 "func.*HandleTask" pkg/tasks/ --type go | head -100

Repository: ConductorOne/baton-sdk

Length of output: 6230


🏁 Script executed:

# Look for FinishTask calls to see error handling patterns
rg "FinishTask.*err" pkg/tasks/ --type go -B 2 -A 2 | head -80

Repository: ConductorOne/baton-sdk

Length of output: 5271


🏁 Script executed:

# Check list_ticket_schemas error handling for comparison (also does pagination)
cat -n pkg/tasks/c1api/list_ticket_schemas.go | sed -n '30,80p'

Repository: ConductorOne/baton-sdk

Length of output: 1934


🏁 Script executed:

# Check list_event_feeds error handling
cat -n pkg/tasks/c1api/list_event_feeds.go | sed -n '27,70p'

Repository: ConductorOne/baton-sdk

Length of output: 1188


🏁 Script executed:

# Check grant handler error handling for comparison
rg -A 15 "func.*grantTaskHandler.*HandleTask" pkg/tasks/c1api/grant.go | head -40

Repository: ConductorOne/baton-sdk

Length of output: 811


🏁 Script executed:

# Check if there's a pattern: are all list/query handlers using bare return on error?
rg "func.*Handler.*HandleTask" pkg/tasks/c1api/ --type go | grep -i "list\|get\|bulk"

Repository: ConductorOne/baton-sdk

Length of output: 929


🏁 Script executed:

# Look at one more list handler to confirm pattern
cat -n pkg/tasks/c1api/get_ticket.go | sed -n '27,65p'

Repository: ConductorOne/baton-sdk

Length of output: 1558


🏁 Script executed:

# Check list_ticket_schemas full error handling to see if it calls FinishTask on RPC error
cat -n pkg/tasks/c1api/list_ticket_schemas.go | sed -n '50,82p'

Repository: ConductorOne/baton-sdk

Length of output: 1151


Ensure RPC errors in the pagination loop result in FinishTask being called.

Error handling is inconsistent across handlers. When cc.ListEvents fails (line 52–53), you return the error directly instead of calling FinishTask. This leaves the task potentially unfinished. Other handlers like getTicketTaskHandler correctly route RPC errors through FinishTask:

 		if err != nil {
-			return err
+			return c.helpers.FinishTask(ctx, nil, nil, err)
 		}

Minor issues:

  • Span name mismatch: The span name "listEventHandler.HandleTask" should be "listEventsHandler.HandleTask" to match the type name.
  • Annotations from paginated responses: You currently drop annotations from intermediate pages and only pass the final response's annotations. Consider accumulating or merging them if backends rely on this.
🤖 Prompt for AI Agents
In pkg/tasks/c1api/list_events.go around lines 27 to 67, the handler returns RPC
errors directly inside the pagination loop which can leave the task unfinished;
change the error path so any error from cc.ListEvents calls FinishTask with nil
response and the error (and appropriate non-retryable flag if needed) before
returning. Also correct the span name from "listEventHandler.HandleTask" to
"listEventsHandler.HandleTask" to match the type, and while iterating
accumulate/merge annotations from each paginated feeds response into a single
annotations set (rather than only using the final page's annotations) so
backend-provided annotations are preserved when calling FinishTask with the
aggregated response.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
pkg/tasks/c1api/list_event_feeds.go (1)

40-43: Finish task on RPC error to prevent incomplete task state.

When cc.ListEventFeeds fails, returning the error directly likely leaves the task unfinished in the task management system. The task should be explicitly completed via FinishTask so the system knows it's done.

Apply this diff:

 	feeds, err := cc.ListEventFeeds(ctx, &v2.ListEventFeedsRequest{})
 	if err != nil {
-		return err
+		return c.helpers.FinishTask(ctx, nil, nil, err)
 	}
🧹 Nitpick comments (1)
pkg/tasks/c1api/list_event_feeds.go (1)

36-37: Simplify log messages.

The log message and field name are verbose. "get list event feeds task" is awkward phrasing.

Apply this diff:

-		l.Error("get list event feeds task was nil", zap.Any("get_list_event_feeds_task", t))
-		return c.helpers.FinishTask(ctx, nil, nil, errors.Join(errors.New("malformed get list event feeds task"), ErrTaskNonRetryable))
+		l.Error("list event feeds task was nil", zap.Any("list_event_feeds_task", t))
+		return c.helpers.FinishTask(ctx, nil, nil, errors.Join(errors.New("malformed list event feeds task"), ErrTaskNonRetryable))
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cda0dde and c810cdb.

📒 Files selected for processing (2)
  • pkg/tasks/c1api/list_event_feeds.go (1 hunks)
  • pkg/tasks/tasks.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/tasks/tasks.go (2)
pb/c1/connectorapi/baton/v1/baton.pb.go (2)
  • Task_ListEventFeeds_case (928-928)
  • Task_ListEvents_case (929-929)
pkg/types/tasks/tasks.go (2)
  • ListEventFeedsType (97-97)
  • ListEventsType (96-96)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: go-lint
  • GitHub Check: go-test (1.25.2, ubuntu-latest)
  • GitHub Check: go-test (1.25.2, windows-latest)

EventFeedId: t.GetEventFeedId(),
StartAt: t.GetStartAt(),
Cursor: pageToken,
PageSize: t.GetPageSize(),
Copy link
Contributor

Choose a reason for hiding this comment

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

I thought the page size was to limit the number of events to fetch, not an implementation detail of how many events to fetch at a time. I'm pretty sure we want a way to limit the number of events we get back. Also we should think about how we can avoid hitting GRPC message size limits.

I think the simplest thing would be to mirror ListEventsRequest/Response. Allow requesting events with a timestamp or an opaque cursor, and have the response contain a cursor and a has_more bool.

@Bencheng21 Bencheng21 force-pushed the DUCT13790-listing_events branch from c810cdb to d19529a Compare January 17, 2026 00:26
@Bencheng21 Bencheng21 requested a review from ggreer January 20, 2026 17:58
Copy link
Contributor

@jugonzalez12 jugonzalez12 left a comment

Choose a reason for hiding this comment

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

lgtm

repeated google.protobuf.Any annotations = 1;
google.protobuf.Timestamp start_at = 2;
string event_feed_id = 3;
uint32 page_size = 4;
Copy link
Contributor

Choose a reason for hiding this comment

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

we don't need a cursor like

string cursor = 1 [(validate.rules).string = {
?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good catch. thanks

@Bencheng21 Bencheng21 force-pushed the DUCT13790-listing_events branch from d19529a to 5800b4a Compare January 22, 2026 18:33
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.

5 participants