Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(taskbroker): Enable querying for namespace specific tasks #74

Merged
merged 12 commits into from
Dec 9, 2024

Conversation

enochtangg
Copy link
Member

@enochtangg enochtangg commented Dec 5, 2024

Overview:
This PR is responsible enabling taskbroker to receive a namespace parameter for the worker client and return pending activations specific for that namespace.

Dependencies:

Refs:

Testing:

  • Unit test added below
  • Tested end-to-end with taskworker

@enochtangg enochtangg requested a review from a team as a code owner December 5, 2024 19:22
@enochtangg enochtangg changed the title Enoch/fetch task by namespace feat(taskbroker): Enable querying for namespace specific tasks Dec 5, 2024
Comment on lines 88 to 89
if let Some(fetch_next) = request.get_ref().fetch_next {
if fetch_next {
Copy link
Member

Choose a reason for hiding this comment

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

Having to provide both fetch_next and fetch_next_namespace creates a trap where providing fetch_next_namespace in isolation will be silently ignored. Perhaps we need two cases, one for fetch_next and one for fetch_next_namespace?

Copy link
Member

@john-z-yang john-z-yang Dec 6, 2024

Choose a reason for hiding this comment

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

+1, would it make more sense to redefine fetch_next using a richer type?

Like

fetch_next: Option<Fetch>

Enum Fetch {
    Arbitrary,
    ByNamespace(String)
}

I'm not sure how to express this in protobuf and how it will translate via prost, maybe something like

message GetTaskResponse {
    ...
    optional fetchNext fetchNext = 1;
}

message fetchNext {
    oneof fetchBy {
        string namespace = 1;
        google.protobuf.NullValue arbitrary = 2;
    }
}

Copy link
Member

Choose a reason for hiding this comment

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

A oneof could work, I don't think we would need the nested message either.

message SetTaskStatusRequest {
  oneof fetch_next_by {
      string fetch_namespace = 6;
      bool fetch_any = 7;
  }
}

We might also be able to adapt the existing fields into a oneof as oneof doesn't use up slots in the proto.

Copy link
Member

@john-z-yang john-z-yang Dec 6, 2024

Choose a reason for hiding this comment

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

I see, so with

message SetTaskStatusRequest {
  oneof fetch_next_by {
      string fetch_namespace = 6;
      bool fetch_any = 7;
  }
}

If use caller does not want to fetch another message, they would set the fetch_any variant to false?

Copy link
Member

Choose a reason for hiding this comment

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

If use caller does not want to fetch another message, they would set the fetch_any variant to false?

Yeah, it can also be left empty (at least in the python bindings).

message SetTaskStatusRequest {
  string id = 1;
  TaskActivationStatus status = 3;

  // Set to true to have receive a new task in the response
  optional bool fetch_next = 4;
  optional string fetch_next_namespace = 5;

  oneof fetch_next_by {
      string fetch_namespace = 6;
      bool fetch_any = 7;
  }
}

And usage of the generated python code

from sentry_protos.sentry.v1.taskworker_pb2 import SetTaskStatusRequest
from sentry_protos.sentry.v1.taskworker_pb2 import TASK_ACTIVATION_STATUS_COMPLETE

>>> req = SetTaskStatusRequest(id="abc", status=TASK_ACTIVATION_STATUS_COMPLETE)
>>> req.fetch_any
False
>>> req.fetch_namespace
''
>>> req = SetTaskStatusRequest(id="abc", status=TASK_ACTIVATION_STATUS_COMPLETE, fetch_any=True)
>>> req.fetch_any
True
>>> req = SetTaskStatusRequest(id="abc", status=TASK_ACTIVATION_STATUS_COMPLETE, fetch_any=True, fetch_namespace="derp")
>>> req
id: "abc"
status: TASK_ACTIVATION_STATUS_COMPLETE
fetch_namespace: "derp"

>>> req.fetch_any
False

It doesn't seem like the generated code will raise an error if both are provided, but only one value is set into the object.

Copy link
Member

Choose a reason for hiding this comment

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

Ah okay, personally a oneof with a string/bool variant is a little less intuitive than an optional oneof with a string/unit variant for some reason. But I think either is serviceable and it seems like the former is more easily expressed in protobuf.

Copy link
Member Author

@enochtangg enochtangg Dec 6, 2024

Choose a reason for hiding this comment

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

What if we just use made the fetch_next message itself optional, and use that to replace fetch_any. It feel like it could be a bit more intuitive than using oneof at all?

For example:

message FetchNext {
  optional string namespace = 1;
}

message SetTaskStatusRequest {
  string id = 1;
  TaskActivationStatus status = 2;

  // If fetch_next is provided, receive a new task in the response
  optional FetchNext fetch_next = 3;
}

as defined in getsentry/sentry-protos#69

Copy link
Member

Choose a reason for hiding this comment

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

That works too!

Copy link
Member

@markstory markstory Dec 6, 2024

Choose a reason for hiding this comment

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

We should also update the worker in sentry to use the undeprecated parameters.

Comment on lines 207 to 220
"UPDATE inflight_taskactivations
SET
processing_deadline = datetime('now', '+' || processing_deadline_duration || ' seconds'),
status = $1
WHERE id = (
SELECT id
FROM inflight_taskactivations
WHERE status = $2
AND (deadletter_at IS NULL OR deadletter_at > $3)
AND namespace = $4
ORDER BY added_at
LIMIT 1
)
RETURNING *",
Copy link
Member

Choose a reason for hiding this comment

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

You might be able to use QueryBuilder to reduce the duplication in these queries. You could initialize the query with the query up to the namespace condition, and then use .push() and .push_bind() to add the namespace condition and limit/returning clauses.

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated, using query builder 👍 Though, I find it a bit less legible because query builder requires use to build it piecewise

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I miss having an ORM style builder. But I also don't think we have enough complex queries to justify a larger library yet.

@enochtangg enochtangg force-pushed the enoch/fetch-task-by-namespace branch 3 times, most recently from 1880d83 to 576a656 Compare December 6, 2024 20:14
Copy link
Member

@markstory markstory left a comment

Choose a reason for hiding this comment

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

Looking good.

Comment on lines 242 to 246
query_builder.push(" ORDER BY added_at LIMIT 1) RETURNING *");
query_builder
.build_query_as::<TableRow>()
.fetch_optional(&self.sqlite_pool)
.await?
Copy link
Member

Choose a reason for hiding this comment

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

This passage looks the same on both sides of the match arms, could it be moved down? You'd have to move the result assignment down as well though.

@enochtangg enochtangg force-pushed the enoch/fetch-task-by-namespace branch from 576a656 to 6219a7a Compare December 6, 2024 22:41
@enochtangg enochtangg merged commit a62bd12 into main Dec 9, 2024
5 checks passed
@enochtangg enochtangg deleted the enoch/fetch-task-by-namespace branch December 9, 2024 15:37
@enochtangg enochtangg linked an issue Dec 9, 2024 that may be closed by this pull request
enochtangg added a commit to getsentry/sentry that referenced this pull request Dec 10, 2024
Now that taskbroker gRPC supports getting tasks by namespace, this PR
enables the taskworker to use that parameter if provided.


Depends on: getsentry/taskbroker#74
mifu67 pushed a commit to getsentry/sentry that referenced this pull request Dec 10, 2024
Now that taskbroker gRPC supports getting tasks by namespace, this PR
enables the taskworker to use that parameter if provided.


Depends on: getsentry/taskbroker#74
andrewshie-sentry pushed a commit to getsentry/sentry that referenced this pull request Jan 2, 2025
Now that taskbroker gRPC supports getting tasks by namespace, this PR
enables the taskworker to use that parameter if provided.


Depends on: getsentry/taskbroker#74
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.

Implement the namespace parameter for GetTask
3 participants