// The MIT License
//
// Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

syntax = "proto3";

package temporal.api.taskqueue.v1;

option go_package = "go.temporal.io/api/taskqueue/v1;taskqueue";
option java_package = "io.temporal.api.taskqueue.v1";
option java_multiple_files = true;
option java_outer_classname = "MessageProto";
option ruby_package = "Temporalio::Api::TaskQueue::V1";
option csharp_namespace = "Temporalio.Api.TaskQueue.V1";

import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";

import "temporal/api/enums/v1/task_queue.proto";
import "temporal/api/common/v1/message.proto";

// See https://docs.temporal.io/docs/concepts/task-queues/
message TaskQueue {
    string name = 1;
    // Default: TASK_QUEUE_KIND_NORMAL.
    temporal.api.enums.v1.TaskQueueKind kind = 2;
    // Iff kind == TASK_QUEUE_KIND_STICKY, then this field contains the name of
    // the normal task queue that the sticky worker is running on.
    string normal_name = 3;
}

// Only applies to activity task queues
message TaskQueueMetadata {
    // Allows throttling dispatch of tasks from this queue
    google.protobuf.DoubleValue max_tasks_per_second = 1;
}

// Used for specifying versions the caller is interested in.
message TaskQueueVersionSelection {
    // Include specific Build IDs.
    repeated string build_ids = 1;
    // Include the unversioned queue.
    bool unversioned = 2;
    // Include all active versions. A version is considered active if it has had new
    // tasks or polls recently.
    bool all_active = 3;
}

message TaskQueueVersionInfo {
    // Task Queue info per Task Type. Key is the numerical value of the temporal.api.enums.v1.TaskQueueType enum.
    map<int32, TaskQueueTypeInfo> types_info = 1;

    // Task Reachability is eventually consistent; there may be a delay until it converges to the most
    // accurate value but it is designed in a way to take the more conservative side until it converges.
    // For example REACHABLE is more conservative than CLOSED_WORKFLOWS_ONLY.
    //
    // Note: future activities who inherit their workflow's Build ID but not its Task Queue will not be
    // accounted for reachability as server cannot know if they'll happen as they do not use
    // assignment rules of their Task Queue. Same goes for Child Workflows or Continue-As-New Workflows
    // who inherit the parent/previous workflow's Build ID but not its Task Queue. In those cases, make
    // sure to query reachability for the parent/previous workflow's Task Queue as well.
    temporal.api.enums.v1.BuildIdTaskReachability task_reachability = 2;
}

message TaskQueueTypeInfo {
    // Unversioned workers (with `useVersioning=false`) are reported in unversioned result even if they set a Build ID.
    repeated PollerInfo pollers = 1;
    TaskQueueStats stats = 2;
}

// For workflow task queues, we only report the normal queue stats, not sticky queues. This means the stats
// reported here do not count all workflow tasks. However, because the tasks queued in sticky queues only remain
// valid for a few seconds, the inaccuracy becomes less significant as the backlog age grows.
message TaskQueueStats {
    // The approximate number of tasks backlogged in this task queue. May count expired tasks but eventually converges
    // to the right value.
    int64 approximate_backlog_count = 1;
    // Approximate age of the oldest task in the backlog based on the create timestamp of the task at the head of the queue.
    google.protobuf.Duration approximate_backlog_age = 2;
    // Approximate tasks per second added to the task queue based on activity within a fixed window. This includes both backlogged and
    // sync-matched tasks.
    float tasks_add_rate = 3;
    // Approximate tasks per second dispatched to workers based on activity within a fixed window. This includes both backlogged and
    // sync-matched tasks.
    float tasks_dispatch_rate = 4;
}

// Deprecated. Use `InternalTaskQueueStatus`. This is kept until `DescribeTaskQueue` supports legacy behavior.
message TaskQueueStatus {
    int64 backlog_count_hint = 1;
    int64 read_level = 2;
    int64 ack_level = 3;
    double rate_per_second = 4;
    TaskIdBlock task_id_block = 5;
}

message TaskIdBlock {
    int64 start_id = 1;
    int64 end_id = 2;
}

message TaskQueuePartitionMetadata {
    string key = 1;
    string owner_host_name = 2;
}

message PollerInfo {
    google.protobuf.Timestamp last_access_time = 1;
    string identity = 2;
    double rate_per_second = 3;
    // If a worker has opted into the worker versioning feature while polling, its capabilities will
    // appear here.
    temporal.api.common.v1.WorkerVersionCapabilities worker_version_capabilities = 4;
}

message StickyExecutionAttributes {
    TaskQueue worker_task_queue = 1;
    // (-- api-linter: core::0140::prepositions=disabled
    //     aip.dev/not-precedent: "to" is used to indicate interval. --)
    google.protobuf.Duration schedule_to_start_timeout = 2;
}

// Used by the worker versioning APIs, represents an unordered set of one or more versions which are
// considered to be compatible with each other. Currently the versions are always worker build IDs.
message CompatibleVersionSet {
    // All the compatible versions, unordered, except for the last element, which is considered the set "default".
    repeated string build_ids = 1;
}

// Reachability of tasks for a worker on a single task queue.
message TaskQueueReachability {
    string task_queue = 1;
    // Task reachability for a worker in a single task queue.
    // See the TaskReachability docstring for information about each enum variant.
    // If reachability is empty, this worker is considered unreachable in this task queue.
    repeated temporal.api.enums.v1.TaskReachability reachability = 2;
}

// Reachability of tasks for a worker by build id, in one or more task queues.
message BuildIdReachability {
    // A build id or empty if unversioned.
    string build_id = 1;
    // Reachability per task queue.
    repeated TaskQueueReachability task_queue_reachability = 2;
}

message RampByPercentage {
    // Acceptable range is [0,100).
    float ramp_percentage = 1;
}

// Assignment rules are applied to *new* Workflow and Activity executions at
// schedule time to assign them to a Build ID.
//
// Assignment rules will not be used in the following cases:
//    - Child Workflows or Continue-As-New Executions who inherit their
//      parent/previous Workflow's assigned Build ID (by setting the
//      `inherit_build_id` flag - default behavior in SDKs when the same Task Queue
//      is used.)
//    - An Activity that inherits the assigned Build ID of its Workflow (by
//      setting the `use_workflow_build_id` flag - default behavior in SDKs
//      when the same Task Queue is used.)
//
// In absence of (applicable) redirect rules (`CompatibleBuildIdRedirectRule`s)
// the task will be dispatched to Workers of the Build ID determined by the
// assignment rules (or inherited). Otherwise, the final Build ID will be
// determined by the redirect rules.
//
// Once a Workflow completes its first Workflow Task in a particular Build ID it
// stays in that Build ID regardless of changes to assignment rules. Redirect
// rules can be used to move the workflow to another compatible Build ID.
//
// When using Worker Versioning on a Task Queue, in the steady state,
// there should typically be a single assignment rule to send all new executions
// to the latest Build ID. Existence of at least one such "unconditional"
// rule at all times is enforces by the system, unless the `force` flag is used
// by the user when replacing/deleting these rules (for exceptional cases).
//
// During a deployment, one or more additional rules can be added to assign a
// subset of the tasks to a new Build ID based on a "ramp percentage".
//
// When there are multiple assignment rules for a Task Queue, the rules are
// evaluated in order, starting from index 0. The first applicable rule will be
// applied and the rest will be ignored.
//
// In the event that no assignment rule is applicable on a task (or the Task
// Queue is simply not versioned), the tasks will be dispatched to an
// unversioned Worker.
message BuildIdAssignmentRule {
    string target_build_id = 1;

    // If a ramp is provided, this rule will be applied only to a sample of
    // tasks according to the provided percentage.
    // This option can be used only on "terminal" Build IDs (the ones not used
    // as source in any redirect rules).
    oneof ramp {
        // This ramp is useful for gradual Blue/Green deployments (and similar)
        // where you want to send a certain portion of the traffic to the target
        // Build ID.
        RampByPercentage percentage_ramp = 3;
    }
}

// These rules apply to tasks assigned to a particular Build ID
// (`source_build_id`) to redirect them to another *compatible* Build ID
// (`target_build_id`).
//
// It is user's responsibility to ensure that the target Build ID is compatible
// with the source Build ID (e.g. by using the Patching API).
//
// Most deployments are not expected to need these rules, however following
// situations can greatly benefit from redirects:
//  - Need to move long-running Workflow Executions from an old Build ID to a
//    newer one.
//  - Need to hotfix some broken or stuck Workflow Executions.
//
// In steady state, redirect rules are beneficial when dealing with old
// Executions ran on now-decommissioned Build IDs:
//  - To redirecting the Workflow Queries to the current (compatible) Build ID.
//  - To be able to Reset an old Execution so it can run on the current
//    (compatible) Build ID.
//
// Redirect rules can be chained.
message CompatibleBuildIdRedirectRule {
    string source_build_id = 1;
    // Target Build ID must be compatible with the Source Build ID; that is it
    // must be able to process event histories made by the Source Build ID by
    // using [Patching](https://docs.temporal.io/workflows#patching) or other
    // means.
    string target_build_id = 2;
}

message TimestampedBuildIdAssignmentRule {
    BuildIdAssignmentRule rule = 1;
    google.protobuf.Timestamp create_time = 2;
}

message TimestampedCompatibleBuildIdRedirectRule {
    CompatibleBuildIdRedirectRule rule = 1;
    google.protobuf.Timestamp create_time = 2;
}