ringo-task-queue 0.1.0.dev1__py3-none-win_amd64.whl → 0.1.0.dev2__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -28,7 +28,7 @@ from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2
28
28
  from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
29
29
 
30
30
 
31
- DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n,ringo_task_queue/_proto/ringo/v1/queue.proto\x12\x08ringo.v1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"i\n\x10NegotiateRequest\x12\x10\n\x08sdk_name\x18\x01 \x01(\t\x12\x13\n\x0bsdk_version\x18\x02 \x01(\t\x12\x16\n\x0eprotocol_major\x18\x03 \x01(\r\x12\x16\n\x0eprotocol_minor\x18\x04 \x01(\r\"\x88\x01\n\x11NegotiateResponse\x12\x16\n\x0eserver_version\x18\x01 \x01(\t\x12\x16\n\x0eprotocol_major\x18\x02 \x01(\r\x12\x16\n\x0eprotocol_minor\x18\x03 \x01(\r\x12\x14\n\x0c\x63\x61pabilities\x18\x04 \x03(\t\x12\x15\n\rsession_token\x18\x05 \x01(\t\"W\n\x0eRequestContext\x12\x16\n\x0eprotocol_major\x18\x01 \x01(\r\x12\x16\n\x0eprotocol_minor\x18\x02 \x01(\r\x12\x15\n\rsession_token\x18\x03 \x01(\t\"\xbd\x01\n\x0b\x45rrorDetail\x12!\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x13.ringo.v1.ErrorCode\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x12\n\nrequest_id\x18\x03 \x01(\t\x12\x35\n\x08metadata\x18\x04 \x03(\x0b\x32#.ringo.v1.ErrorDetail.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xed\x01\n\x0bRetryPolicy\x12\x14\n\x0cmax_attempts\x18\x01 \x01(\r\x12)\n\x08strategy\x18\x02 \x01(\x0e\x32\x17.ringo.v1.RetryStrategy\x12\x30\n\rinitial_delay\x18\x03 \x01(\x0b\x32\x19.google.protobuf.Duration\x12,\n\tmax_delay\x18\x04 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x12\n\nmultiplier\x18\x05 \x01(\x01\x12\x0e\n\x06jitter\x18\x06 \x01(\x01\x12\x19\n\x11\x64\x65\x63rease_priority\x18\x07 \x01(\x08\"\xc6\x01\n\x08TaskSpec\x12\x12\n\nunique_key\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\'\n\x07payload\x18\x03 \x01(\x0b\x32\x16.google.protobuf.Value\x12\x10\n\x08priority\x18\x04 \x01(\x05\x12+\n\x0cretry_policy\x18\x05 \x01(\x0b\x32\x15.ringo.v1.RetryPolicy\x12\x30\n\x0c\x61vailable_at\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xb8\x04\n\x04Task\x12\n\n\x02id\x18\x01 \x01(\t\x12\r\n\x05queue\x18\x02 \x01(\t\x12\x12\n\nunique_key\x18\x03 \x01(\t\x12\x0c\n\x04type\x18\x04 \x01(\t\x12\'\n\x07payload\x18\x05 \x01(\x0b\x32\x16.google.protobuf.Value\x12\x10\n\x08priority\x18\x06 \x01(\x05\x12$\n\x06status\x18\x07 \x01(\x0e\x32\x14.ringo.v1.TaskStatus\x12\x0f\n\x07\x61ttempt\x18\x08 \x01(\r\x12\x14\n\x0cmax_attempts\x18\t \x01(\r\x12\x30\n\x0c\x61vailable_at\x18\n \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\ncreated_at\x18\x0b \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\nupdated_at\x18\x0c \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x30\n\x0c\x63ompleted_at\x18\r \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x12\n\nlast_error\x18\x0e \x01(\t\x12\x1c\n\x14last_error_truncated\x18\x0f \x01(\x08\x12#\n\x08\x61ttempts\x18\x10 \x03(\x0b\x32\x11.ringo.v1.Attempt\x12$\n\x08progress\x18\x11 \x01(\x0b\x32\x12.ringo.v1.Progress\x12*\n\rcurrent_lease\x18\x12 \x01(\x0b\x32\x13.ringo.v1.LeaseInfo\"\xc6\x01\n\x07\x41ttempt\x12\x0e\n\x06number\x18\x01 \x01(\r\x12\x11\n\tworker_id\x18\x02 \x01(\t\x12.\n\nstarted_at\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12/\n\x0b\x66inished_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0f\n\x07outcome\x18\x05 \x01(\t\x12\r\n\x05\x65rror\x18\x06 \x01(\t\x12\x17\n\x0f\x65rror_truncated\x18\x07 \x01(\x08\"k\n\x08Progress\x12\x0f\n\x07\x63urrent\x18\x01 \x01(\x01\x12\r\n\x05total\x18\x02 \x01(\x01\x12\x0f\n\x07message\x18\x03 \x01(\t\x12.\n\nupdated_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"Z\n\tLeaseInfo\x12\x0f\n\x07\x61ttempt\x18\x01 \x01(\r\x12\x11\n\tworker_id\x18\x02 \x01(\t\x12)\n\x05until\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"|\n\x05Lease\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x61ttempt\x18\x02 \x01(\r\x12\x13\n\x0blease_token\x18\x03 \x01(\t\x12\x11\n\tworker_id\x18\x04 \x01(\t\x12)\n\x05until\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"J\n\nLeasedTask\x12\x1c\n\x04task\x18\x01 \x01(\x0b\x32\x0e.ringo.v1.Task\x12\x1e\n\x05lease\x18\x02 \x01(\x0b\x32\x0f.ringo.v1.Lease\"l\n\x0e\x45nqueueRequest\x12\r\n\x05queue\x18\x01 \x01(\t\x12 \n\x04task\x18\x02 \x01(\x0b\x32\x12.ringo.v1.TaskSpec\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"O\n\rEnqueueResult\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x63reated\x18\x02 \x01(\x08\x12\x1c\n\x04task\x18\x03 \x01(\x0b\x32\x0e.ringo.v1.Task\":\n\x0f\x45nqueueResponse\x12\'\n\x06result\x18\x01 \x01(\x0b\x32\x17.ringo.v1.EnqueueResult\"q\n\x12\x45nqueueManyRequest\x12\r\n\x05queue\x18\x01 \x01(\t\x12!\n\x05tasks\x18\x02 \x03(\x0b\x32\x12.ringo.v1.TaskSpec\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"o\n\x13\x45nqueueManyResponse\x12(\n\x07results\x18\x01 \x03(\x0b\x32\x17.ringo.v1.EnqueueResult\x12\x15\n\rcreated_count\x18\x02 \x01(\r\x12\x17\n\x0f\x64uplicate_count\x18\x03 \x01(\r\"z\n\x0eGetTaskRequest\x12\r\n\x05queue\x18\x01 \x01(\t\x12\x11\n\x07task_id\x18\x02 \x01(\tH\x00\x12\x14\n\nunique_key\x18\x03 \x01(\tH\x00\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContextB\x05\n\x03key\"/\n\x0fGetTaskResponse\x12\x1c\n\x04task\x18\x01 \x01(\x0b\x32\x0e.ringo.v1.Task\"|\n\x10RetryTaskRequest\x12\r\n\x05queue\x18\x01 \x01(\t\x12\x11\n\x07task_id\x18\x02 \x01(\tH\x00\x12\x14\n\nunique_key\x18\x03 \x01(\tH\x00\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContextB\x05\n\x03key\"1\n\x11RetryTaskResponse\x12\x1c\n\x04task\x18\x01 \x01(\x0b\x32\x0e.ringo.v1.Task\"\xe2\x01\n\x0c\x43laimRequest\x12\r\n\x05queue\x18\x01 \x01(\t\x12\x11\n\tworker_id\x18\x02 \x01(\t\x12\x12\n\ntask_types\x18\x03 \x03(\t\x12\r\n\x05limit\x18\x04 \x01(\r\x12/\n\x0cwait_timeout\x18\x05 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x31\n\x0elease_duration\x18\x06 \x01(\x0b\x32\x19.google.protobuf.Duration\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"4\n\rClaimResponse\x12#\n\x05tasks\x18\x01 \x03(\x0b\x32\x14.ringo.v1.LeasedTask\"A\n\x08LeaseRef\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x61ttempt\x18\x02 \x01(\r\x12\x13\n\x0blease_token\x18\x03 \x01(\t\"Z\n\nAckRequest\x12!\n\x05lease\x18\x01 \x01(\x0b\x32\x12.ringo.v1.LeaseRef\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"\r\n\x0b\x41\x63kResponse\"\xa3\x01\n\x0bNackRequest\x12!\n\x05lease\x18\x01 \x01(\x0b\x32\x12.ringo.v1.LeaseRef\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12\x37\n\x14retry_delay_override\x18\x03 \x01(\x0b\x32\x19.google.protobuf.Duration\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\",\n\x0cNackResponse\x12\x1c\n\x04task\x18\x01 \x01(\x0b\x32\x0e.ringo.v1.Task\"l\n\rRejectRequest\x12!\n\x05lease\x18\x01 \x01(\x0b\x32\x12.ringo.v1.LeaseRef\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\".\n\x0eRejectResponse\x12\x1c\n\x04task\x18\x01 \x01(\x0b\x32\x0e.ringo.v1.Task\"\x90\x01\n\x12\x45xtendLeaseRequest\x12!\n\x05lease\x18\x01 \x01(\x0b\x32\x12.ringo.v1.LeaseRef\x12,\n\textension\x18\x02 \x01(\x0b\x32\x19.google.protobuf.Duration\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"5\n\x13\x45xtendLeaseResponse\x12\x1e\n\x05lease\x18\x01 \x01(\x0b\x32\x0f.ringo.v1.Lease\"\x96\x01\n\x15ReportProgressRequest\x12!\n\x05lease\x18\x01 \x01(\x0b\x32\x12.ringo.v1.LeaseRef\x12\x0f\n\x07\x63urrent\x18\x02 \x01(\x01\x12\r\n\x05total\x18\x03 \x01(\x01\x12\x0f\n\x07message\x18\x04 \x01(\t\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"\x18\n\x16ReportProgressResponse\"\xc1\x01\n\x12WorkerRegistration\x12\r\n\x05queue\x18\x01 \x01(\t\x12\x11\n\tworker_id\x18\x02 \x01(\t\x12\x12\n\ntask_types\x18\x03 \x03(\t\x12\x17\n\x0fmax_concurrency\x18\x04 \x01(\r\x12\x31\n\x0elease_duration\x18\x05 \x01(\x0b\x32\x19.google.protobuf.Duration\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"!\n\x0c\x43reditUpdate\x12\x11\n\tavailable\x18\x01 \x01(\r\"\x1c\n\x0bWorkerDrain\x12\r\n\x05\x62\x65gin\x18\x01 \x01(\x08\"q\n\x10WorkerRegistered\x12\x11\n\tworker_id\x18\x01 \x01(\t\x12\x17\n\x0fmax_concurrency\x18\x02 \x01(\r\x12\x31\n\x0elease_duration\x18\x03 \x01(\x0b\x32\x19.google.protobuf.Duration\"\x8f\x03\n\x0bWorkRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\x04\x12\x30\n\x08register\x18\x02 \x01(\x0b\x32\x1c.ringo.v1.WorkerRegistrationH\x00\x12(\n\x06\x63redit\x18\x03 \x01(\x0b\x32\x16.ringo.v1.CreditUpdateH\x00\x12#\n\x03\x61\x63k\x18\x04 \x01(\x0b\x32\x14.ringo.v1.AckRequestH\x00\x12%\n\x04nack\x18\x05 \x01(\x0b\x32\x15.ringo.v1.NackRequestH\x00\x12)\n\x06reject\x18\x06 \x01(\x0b\x32\x17.ringo.v1.RejectRequestH\x00\x12\x34\n\x0c\x65xtend_lease\x18\x07 \x01(\x0b\x32\x1c.ringo.v1.ExtendLeaseRequestH\x00\x12\x33\n\x08progress\x18\x08 \x01(\x0b\x32\x1f.ringo.v1.ReportProgressRequestH\x00\x12&\n\x05\x64rain\x18\t \x01(\x0b\x32\x15.ringo.v1.WorkerDrainH\x00\x42\x06\n\x04\x62ody\"F\n\nWorkResult\x12\x12\n\nrequest_id\x18\x01 \x01(\x04\x12$\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x15.ringo.v1.ErrorDetail\"\xc7\x01\n\x0cWorkResponse\x12$\n\x04task\x18\x01 \x01(\x0b\x32\x14.ringo.v1.LeasedTaskH\x00\x12&\n\x06result\x18\x02 \x01(\x0b\x32\x14.ringo.v1.WorkResultH\x00\x12/\n\theartbeat\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x12\x30\n\nregistered\x18\x04 \x01(\x0b\x32\x1a.ringo.v1.WorkerRegisteredH\x00\x42\x06\n\x04\x62ody*\xbf\x01\n\nTaskStatus\x12\x1b\n\x17TASK_STATUS_UNSPECIFIED\x10\x00\x12\x19\n\x15TASK_STATUS_SCHEDULED\x10\x01\x12\x15\n\x11TASK_STATUS_READY\x10\x02\x12\x16\n\x12TASK_STATUS_LEASED\x10\x03\x12\x19\n\x15TASK_STATUS_SUCCEEDED\x10\x04\x12\x14\n\x10TASK_STATUS_DEAD\x10\x05\x12\x19\n\x15TASK_STATUS_CANCELLED\x10\x06*i\n\rRetryStrategy\x12\x1e\n\x1aRETRY_STRATEGY_UNSPECIFIED\x10\x00\x12\x18\n\x14RETRY_STRATEGY_FIXED\x10\x01\x12\x1e\n\x1aRETRY_STRATEGY_EXPONENTIAL\x10\x02*\xac\x02\n\tErrorCode\x12\x1a\n\x16\x45RROR_CODE_UNSPECIFIED\x10\x00\x12\x1f\n\x1b\x45RROR_CODE_INVALID_ARGUMENT\x10\x01\x12\x18\n\x14\x45RROR_CODE_DUPLICATE\x10\x02\x12\x18\n\x14\x45RROR_CODE_NOT_FOUND\x10\x03\x12\x17\n\x13\x45RROR_CODE_CONFLICT\x10\x04\x12\x19\n\x15\x45RROR_CODE_LEASE_LOST\x10\x05\x12\x1a\n\x16\x45RROR_CODE_UNAVAILABLE\x10\x06\x12 \n\x1c\x45RROR_CODE_DEADLINE_EXCEEDED\x10\x07\x12#\n\x1f\x45RROR_CODE_INCOMPATIBLE_VERSION\x10\x08\x12\x17\n\x13\x45RROR_CODE_INTERNAL\x10\t2\xa4\x06\n\x0cQueueService\x12\x44\n\tNegotiate\x12\x1a.ringo.v1.NegotiateRequest\x1a\x1b.ringo.v1.NegotiateResponse\x12>\n\x07\x45nqueue\x12\x18.ringo.v1.EnqueueRequest\x1a\x19.ringo.v1.EnqueueResponse\x12J\n\x0b\x45nqueueMany\x12\x1c.ringo.v1.EnqueueManyRequest\x1a\x1d.ringo.v1.EnqueueManyResponse\x12>\n\x07GetTask\x12\x18.ringo.v1.GetTaskRequest\x1a\x19.ringo.v1.GetTaskResponse\x12\x44\n\tRetryTask\x12\x1a.ringo.v1.RetryTaskRequest\x1a\x1b.ringo.v1.RetryTaskResponse\x12\x38\n\x05\x43laim\x12\x16.ringo.v1.ClaimRequest\x1a\x17.ringo.v1.ClaimResponse\x12\x32\n\x03\x41\x63k\x12\x14.ringo.v1.AckRequest\x1a\x15.ringo.v1.AckResponse\x12\x35\n\x04Nack\x12\x15.ringo.v1.NackRequest\x1a\x16.ringo.v1.NackResponse\x12;\n\x06Reject\x12\x17.ringo.v1.RejectRequest\x1a\x18.ringo.v1.RejectResponse\x12J\n\x0b\x45xtendLease\x12\x1c.ringo.v1.ExtendLeaseRequest\x1a\x1d.ringo.v1.ExtendLeaseResponse\x12S\n\x0eReportProgress\x12\x1f.ringo.v1.ReportProgressRequest\x1a .ringo.v1.ReportProgressResponse\x12\x39\n\x04Work\x12\x15.ringo.v1.WorkRequest\x1a\x16.ringo.v1.WorkResponse(\x01\x30\x01\x42l\n\x16\x64\x65v.ringo.taskqueue.v1B\nQueueProtoP\x01ZDgithub.com/ringo-task-queue/ringo-task-queue/gen/go/ringo/v1;ringov1b\x06proto3')
31
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n,ringo_task_queue/_proto/ringo/v1/queue.proto\x12\x08ringo.v1\x1a\x1egoogle/protobuf/duration.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"i\n\x10NegotiateRequest\x12\x10\n\x08sdk_name\x18\x01 \x01(\t\x12\x13\n\x0bsdk_version\x18\x02 \x01(\t\x12\x16\n\x0eprotocol_major\x18\x03 \x01(\r\x12\x16\n\x0eprotocol_minor\x18\x04 \x01(\r\"\x88\x01\n\x11NegotiateResponse\x12\x16\n\x0eserver_version\x18\x01 \x01(\t\x12\x16\n\x0eprotocol_major\x18\x02 \x01(\r\x12\x16\n\x0eprotocol_minor\x18\x03 \x01(\r\x12\x14\n\x0c\x63\x61pabilities\x18\x04 \x03(\t\x12\x15\n\rsession_token\x18\x05 \x01(\t\"W\n\x0eRequestContext\x12\x16\n\x0eprotocol_major\x18\x01 \x01(\r\x12\x16\n\x0eprotocol_minor\x18\x02 \x01(\r\x12\x15\n\rsession_token\x18\x03 \x01(\t\"\xbd\x01\n\x0b\x45rrorDetail\x12!\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x13.ringo.v1.ErrorCode\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x12\n\nrequest_id\x18\x03 \x01(\t\x12\x35\n\x08metadata\x18\x04 \x03(\x0b\x32#.ringo.v1.ErrorDetail.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xed\x01\n\x0bRetryPolicy\x12\x14\n\x0cmax_attempts\x18\x01 \x01(\r\x12)\n\x08strategy\x18\x02 \x01(\x0e\x32\x17.ringo.v1.RetryStrategy\x12\x30\n\rinitial_delay\x18\x03 \x01(\x0b\x32\x19.google.protobuf.Duration\x12,\n\tmax_delay\x18\x04 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x12\n\nmultiplier\x18\x05 \x01(\x01\x12\x0e\n\x06jitter\x18\x06 \x01(\x01\x12\x19\n\x11\x64\x65\x63rease_priority\x18\x07 \x01(\x08\"\xc6\x01\n\x08TaskSpec\x12\x12\n\nunique_key\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\'\n\x07payload\x18\x03 \x01(\x0b\x32\x16.google.protobuf.Value\x12\x10\n\x08priority\x18\x04 \x01(\x05\x12+\n\x0cretry_policy\x18\x05 \x01(\x0b\x32\x15.ringo.v1.RetryPolicy\x12\x30\n\x0c\x61vailable_at\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xb8\x04\n\x04Task\x12\n\n\x02id\x18\x01 \x01(\t\x12\r\n\x05queue\x18\x02 \x01(\t\x12\x12\n\nunique_key\x18\x03 \x01(\t\x12\x0c\n\x04type\x18\x04 \x01(\t\x12\'\n\x07payload\x18\x05 \x01(\x0b\x32\x16.google.protobuf.Value\x12\x10\n\x08priority\x18\x06 \x01(\x05\x12$\n\x06status\x18\x07 \x01(\x0e\x32\x14.ringo.v1.TaskStatus\x12\x0f\n\x07\x61ttempt\x18\x08 \x01(\r\x12\x14\n\x0cmax_attempts\x18\t \x01(\r\x12\x30\n\x0c\x61vailable_at\x18\n \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\ncreated_at\x18\x0b \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\nupdated_at\x18\x0c \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x30\n\x0c\x63ompleted_at\x18\r \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x12\n\nlast_error\x18\x0e \x01(\t\x12\x1c\n\x14last_error_truncated\x18\x0f \x01(\x08\x12#\n\x08\x61ttempts\x18\x10 \x03(\x0b\x32\x11.ringo.v1.Attempt\x12$\n\x08progress\x18\x11 \x01(\x0b\x32\x12.ringo.v1.Progress\x12*\n\rcurrent_lease\x18\x12 \x01(\x0b\x32\x13.ringo.v1.LeaseInfo\"\xc6\x01\n\x07\x41ttempt\x12\x0e\n\x06number\x18\x01 \x01(\r\x12\x11\n\tworker_id\x18\x02 \x01(\t\x12.\n\nstarted_at\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12/\n\x0b\x66inished_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0f\n\x07outcome\x18\x05 \x01(\t\x12\r\n\x05\x65rror\x18\x06 \x01(\t\x12\x17\n\x0f\x65rror_truncated\x18\x07 \x01(\x08\"k\n\x08Progress\x12\x0f\n\x07\x63urrent\x18\x01 \x01(\x01\x12\r\n\x05total\x18\x02 \x01(\x01\x12\x0f\n\x07message\x18\x03 \x01(\t\x12.\n\nupdated_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"Z\n\tLeaseInfo\x12\x0f\n\x07\x61ttempt\x18\x01 \x01(\r\x12\x11\n\tworker_id\x18\x02 \x01(\t\x12)\n\x05until\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"|\n\x05Lease\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x61ttempt\x18\x02 \x01(\r\x12\x13\n\x0blease_token\x18\x03 \x01(\t\x12\x11\n\tworker_id\x18\x04 \x01(\t\x12)\n\x05until\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"J\n\nLeasedTask\x12\x1c\n\x04task\x18\x01 \x01(\x0b\x32\x0e.ringo.v1.Task\x12\x1e\n\x05lease\x18\x02 \x01(\x0b\x32\x0f.ringo.v1.Lease\"l\n\x0e\x45nqueueRequest\x12\r\n\x05queue\x18\x01 \x01(\t\x12 \n\x04task\x18\x02 \x01(\x0b\x32\x12.ringo.v1.TaskSpec\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"O\n\rEnqueueResult\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x63reated\x18\x02 \x01(\x08\x12\x1c\n\x04task\x18\x03 \x01(\x0b\x32\x0e.ringo.v1.Task\":\n\x0f\x45nqueueResponse\x12\'\n\x06result\x18\x01 \x01(\x0b\x32\x17.ringo.v1.EnqueueResult\"q\n\x12\x45nqueueManyRequest\x12\r\n\x05queue\x18\x01 \x01(\t\x12!\n\x05tasks\x18\x02 \x03(\x0b\x32\x12.ringo.v1.TaskSpec\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"o\n\x13\x45nqueueManyResponse\x12(\n\x07results\x18\x01 \x03(\x0b\x32\x17.ringo.v1.EnqueueResult\x12\x15\n\rcreated_count\x18\x02 \x01(\r\x12\x17\n\x0f\x64uplicate_count\x18\x03 \x01(\r\"z\n\x0eGetTaskRequest\x12\r\n\x05queue\x18\x01 \x01(\t\x12\x11\n\x07task_id\x18\x02 \x01(\tH\x00\x12\x14\n\nunique_key\x18\x03 \x01(\tH\x00\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContextB\x05\n\x03key\"/\n\x0fGetTaskResponse\x12\x1c\n\x04task\x18\x01 \x01(\x0b\x32\x0e.ringo.v1.Task\"g\n\x17GetQueueActivityRequest\x12\r\n\x05queue\x18\x01 \x01(\t\x12\x12\n\ntask_types\x18\x02 \x03(\t\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"5\n\x18GetQueueActivityResponse\x12\x19\n\x11\x61\x63tive_task_count\x18\x01 \x01(\x04\"|\n\x10RetryTaskRequest\x12\r\n\x05queue\x18\x01 \x01(\t\x12\x11\n\x07task_id\x18\x02 \x01(\tH\x00\x12\x14\n\nunique_key\x18\x03 \x01(\tH\x00\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContextB\x05\n\x03key\"1\n\x11RetryTaskResponse\x12\x1c\n\x04task\x18\x01 \x01(\x0b\x32\x0e.ringo.v1.Task\"\xe2\x01\n\x0c\x43laimRequest\x12\r\n\x05queue\x18\x01 \x01(\t\x12\x11\n\tworker_id\x18\x02 \x01(\t\x12\x12\n\ntask_types\x18\x03 \x03(\t\x12\r\n\x05limit\x18\x04 \x01(\r\x12/\n\x0cwait_timeout\x18\x05 \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x31\n\x0elease_duration\x18\x06 \x01(\x0b\x32\x19.google.protobuf.Duration\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"4\n\rClaimResponse\x12#\n\x05tasks\x18\x01 \x03(\x0b\x32\x14.ringo.v1.LeasedTask\"A\n\x08LeaseRef\x12\x0f\n\x07task_id\x18\x01 \x01(\t\x12\x0f\n\x07\x61ttempt\x18\x02 \x01(\r\x12\x13\n\x0blease_token\x18\x03 \x01(\t\"Z\n\nAckRequest\x12!\n\x05lease\x18\x01 \x01(\x0b\x32\x12.ringo.v1.LeaseRef\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"\r\n\x0b\x41\x63kResponse\"\xa3\x01\n\x0bNackRequest\x12!\n\x05lease\x18\x01 \x01(\x0b\x32\x12.ringo.v1.LeaseRef\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12\x37\n\x14retry_delay_override\x18\x03 \x01(\x0b\x32\x19.google.protobuf.Duration\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\",\n\x0cNackResponse\x12\x1c\n\x04task\x18\x01 \x01(\x0b\x32\x0e.ringo.v1.Task\"l\n\rRejectRequest\x12!\n\x05lease\x18\x01 \x01(\x0b\x32\x12.ringo.v1.LeaseRef\x12\r\n\x05\x65rror\x18\x02 \x01(\t\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\".\n\x0eRejectResponse\x12\x1c\n\x04task\x18\x01 \x01(\x0b\x32\x0e.ringo.v1.Task\"\x90\x01\n\x12\x45xtendLeaseRequest\x12!\n\x05lease\x18\x01 \x01(\x0b\x32\x12.ringo.v1.LeaseRef\x12,\n\textension\x18\x02 \x01(\x0b\x32\x19.google.protobuf.Duration\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"5\n\x13\x45xtendLeaseResponse\x12\x1e\n\x05lease\x18\x01 \x01(\x0b\x32\x0f.ringo.v1.Lease\"\x96\x01\n\x15ReportProgressRequest\x12!\n\x05lease\x18\x01 \x01(\x0b\x32\x12.ringo.v1.LeaseRef\x12\x0f\n\x07\x63urrent\x18\x02 \x01(\x01\x12\r\n\x05total\x18\x03 \x01(\x01\x12\x0f\n\x07message\x18\x04 \x01(\t\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"\x18\n\x16ReportProgressResponse\"\xc1\x01\n\x12WorkerRegistration\x12\r\n\x05queue\x18\x01 \x01(\t\x12\x11\n\tworker_id\x18\x02 \x01(\t\x12\x12\n\ntask_types\x18\x03 \x03(\t\x12\x17\n\x0fmax_concurrency\x18\x04 \x01(\r\x12\x31\n\x0elease_duration\x18\x05 \x01(\x0b\x32\x19.google.protobuf.Duration\x12)\n\x07\x63ontext\x18\x0f \x01(\x0b\x32\x18.ringo.v1.RequestContext\"!\n\x0c\x43reditUpdate\x12\x11\n\tavailable\x18\x01 \x01(\r\"\x1c\n\x0bWorkerDrain\x12\r\n\x05\x62\x65gin\x18\x01 \x01(\x08\"q\n\x10WorkerRegistered\x12\x11\n\tworker_id\x18\x01 \x01(\t\x12\x17\n\x0fmax_concurrency\x18\x02 \x01(\r\x12\x31\n\x0elease_duration\x18\x03 \x01(\x0b\x32\x19.google.protobuf.Duration\"\x8f\x03\n\x0bWorkRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\x04\x12\x30\n\x08register\x18\x02 \x01(\x0b\x32\x1c.ringo.v1.WorkerRegistrationH\x00\x12(\n\x06\x63redit\x18\x03 \x01(\x0b\x32\x16.ringo.v1.CreditUpdateH\x00\x12#\n\x03\x61\x63k\x18\x04 \x01(\x0b\x32\x14.ringo.v1.AckRequestH\x00\x12%\n\x04nack\x18\x05 \x01(\x0b\x32\x15.ringo.v1.NackRequestH\x00\x12)\n\x06reject\x18\x06 \x01(\x0b\x32\x17.ringo.v1.RejectRequestH\x00\x12\x34\n\x0c\x65xtend_lease\x18\x07 \x01(\x0b\x32\x1c.ringo.v1.ExtendLeaseRequestH\x00\x12\x33\n\x08progress\x18\x08 \x01(\x0b\x32\x1f.ringo.v1.ReportProgressRequestH\x00\x12&\n\x05\x64rain\x18\t \x01(\x0b\x32\x15.ringo.v1.WorkerDrainH\x00\x42\x06\n\x04\x62ody\"F\n\nWorkResult\x12\x12\n\nrequest_id\x18\x01 \x01(\x04\x12$\n\x05\x65rror\x18\x02 \x01(\x0b\x32\x15.ringo.v1.ErrorDetail\"\xc7\x01\n\x0cWorkResponse\x12$\n\x04task\x18\x01 \x01(\x0b\x32\x14.ringo.v1.LeasedTaskH\x00\x12&\n\x06result\x18\x02 \x01(\x0b\x32\x14.ringo.v1.WorkResultH\x00\x12/\n\theartbeat\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x12\x30\n\nregistered\x18\x04 \x01(\x0b\x32\x1a.ringo.v1.WorkerRegisteredH\x00\x42\x06\n\x04\x62ody*\xbf\x01\n\nTaskStatus\x12\x1b\n\x17TASK_STATUS_UNSPECIFIED\x10\x00\x12\x19\n\x15TASK_STATUS_SCHEDULED\x10\x01\x12\x15\n\x11TASK_STATUS_READY\x10\x02\x12\x16\n\x12TASK_STATUS_LEASED\x10\x03\x12\x19\n\x15TASK_STATUS_SUCCEEDED\x10\x04\x12\x14\n\x10TASK_STATUS_DEAD\x10\x05\x12\x19\n\x15TASK_STATUS_CANCELLED\x10\x06*i\n\rRetryStrategy\x12\x1e\n\x1aRETRY_STRATEGY_UNSPECIFIED\x10\x00\x12\x18\n\x14RETRY_STRATEGY_FIXED\x10\x01\x12\x1e\n\x1aRETRY_STRATEGY_EXPONENTIAL\x10\x02*\xac\x02\n\tErrorCode\x12\x1a\n\x16\x45RROR_CODE_UNSPECIFIED\x10\x00\x12\x1f\n\x1b\x45RROR_CODE_INVALID_ARGUMENT\x10\x01\x12\x18\n\x14\x45RROR_CODE_DUPLICATE\x10\x02\x12\x18\n\x14\x45RROR_CODE_NOT_FOUND\x10\x03\x12\x17\n\x13\x45RROR_CODE_CONFLICT\x10\x04\x12\x19\n\x15\x45RROR_CODE_LEASE_LOST\x10\x05\x12\x1a\n\x16\x45RROR_CODE_UNAVAILABLE\x10\x06\x12 \n\x1c\x45RROR_CODE_DEADLINE_EXCEEDED\x10\x07\x12#\n\x1f\x45RROR_CODE_INCOMPATIBLE_VERSION\x10\x08\x12\x17\n\x13\x45RROR_CODE_INTERNAL\x10\t2\xff\x06\n\x0cQueueService\x12\x44\n\tNegotiate\x12\x1a.ringo.v1.NegotiateRequest\x1a\x1b.ringo.v1.NegotiateResponse\x12>\n\x07\x45nqueue\x12\x18.ringo.v1.EnqueueRequest\x1a\x19.ringo.v1.EnqueueResponse\x12J\n\x0b\x45nqueueMany\x12\x1c.ringo.v1.EnqueueManyRequest\x1a\x1d.ringo.v1.EnqueueManyResponse\x12>\n\x07GetTask\x12\x18.ringo.v1.GetTaskRequest\x1a\x19.ringo.v1.GetTaskResponse\x12Y\n\x10GetQueueActivity\x12!.ringo.v1.GetQueueActivityRequest\x1a\".ringo.v1.GetQueueActivityResponse\x12\x44\n\tRetryTask\x12\x1a.ringo.v1.RetryTaskRequest\x1a\x1b.ringo.v1.RetryTaskResponse\x12\x38\n\x05\x43laim\x12\x16.ringo.v1.ClaimRequest\x1a\x17.ringo.v1.ClaimResponse\x12\x32\n\x03\x41\x63k\x12\x14.ringo.v1.AckRequest\x1a\x15.ringo.v1.AckResponse\x12\x35\n\x04Nack\x12\x15.ringo.v1.NackRequest\x1a\x16.ringo.v1.NackResponse\x12;\n\x06Reject\x12\x17.ringo.v1.RejectRequest\x1a\x18.ringo.v1.RejectResponse\x12J\n\x0b\x45xtendLease\x12\x1c.ringo.v1.ExtendLeaseRequest\x1a\x1d.ringo.v1.ExtendLeaseResponse\x12S\n\x0eReportProgress\x12\x1f.ringo.v1.ReportProgressRequest\x1a .ringo.v1.ReportProgressResponse\x12\x39\n\x04Work\x12\x15.ringo.v1.WorkRequest\x1a\x16.ringo.v1.WorkResponse(\x01\x30\x01\x42l\n\x16\x64\x65v.ringo.taskqueue.v1B\nQueueProtoP\x01ZDgithub.com/ringo-task-queue/ringo-task-queue/gen/go/ringo/v1;ringov1b\x06proto3')
32
32
 
33
33
  _globals = globals()
34
34
  _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -38,12 +38,12 @@ if not _descriptor._USE_C_DESCRIPTORS:
38
38
  _globals['DESCRIPTOR']._serialized_options = b'\n\026dev.ringo.taskqueue.v1B\nQueueProtoP\001ZDgithub.com/ringo-task-queue/ringo-task-queue/gen/go/ringo/v1;ringov1'
39
39
  _globals['_ERRORDETAIL_METADATAENTRY']._loaded_options = None
40
40
  _globals['_ERRORDETAIL_METADATAENTRY']._serialized_options = b'8\001'
41
- _globals['_TASKSTATUS']._serialized_start=5386
42
- _globals['_TASKSTATUS']._serialized_end=5577
43
- _globals['_RETRYSTRATEGY']._serialized_start=5579
44
- _globals['_RETRYSTRATEGY']._serialized_end=5684
45
- _globals['_ERRORCODE']._serialized_start=5687
46
- _globals['_ERRORCODE']._serialized_end=5987
41
+ _globals['_TASKSTATUS']._serialized_start=5546
42
+ _globals['_TASKSTATUS']._serialized_end=5737
43
+ _globals['_RETRYSTRATEGY']._serialized_start=5739
44
+ _globals['_RETRYSTRATEGY']._serialized_end=5844
45
+ _globals['_ERRORCODE']._serialized_start=5847
46
+ _globals['_ERRORCODE']._serialized_end=6147
47
47
  _globals['_NEGOTIATEREQUEST']._serialized_start=153
48
48
  _globals['_NEGOTIATEREQUEST']._serialized_end=258
49
49
  _globals['_NEGOTIATERESPONSE']._serialized_start=261
@@ -84,50 +84,54 @@ if not _descriptor._USE_C_DESCRIPTORS:
84
84
  _globals['_GETTASKREQUEST']._serialized_end=2897
85
85
  _globals['_GETTASKRESPONSE']._serialized_start=2899
86
86
  _globals['_GETTASKRESPONSE']._serialized_end=2946
87
- _globals['_RETRYTASKREQUEST']._serialized_start=2948
88
- _globals['_RETRYTASKREQUEST']._serialized_end=3072
89
- _globals['_RETRYTASKRESPONSE']._serialized_start=3074
90
- _globals['_RETRYTASKRESPONSE']._serialized_end=3123
91
- _globals['_CLAIMREQUEST']._serialized_start=3126
92
- _globals['_CLAIMREQUEST']._serialized_end=3352
93
- _globals['_CLAIMRESPONSE']._serialized_start=3354
94
- _globals['_CLAIMRESPONSE']._serialized_end=3406
95
- _globals['_LEASEREF']._serialized_start=3408
96
- _globals['_LEASEREF']._serialized_end=3473
97
- _globals['_ACKREQUEST']._serialized_start=3475
98
- _globals['_ACKREQUEST']._serialized_end=3565
99
- _globals['_ACKRESPONSE']._serialized_start=3567
100
- _globals['_ACKRESPONSE']._serialized_end=3580
101
- _globals['_NACKREQUEST']._serialized_start=3583
102
- _globals['_NACKREQUEST']._serialized_end=3746
103
- _globals['_NACKRESPONSE']._serialized_start=3748
104
- _globals['_NACKRESPONSE']._serialized_end=3792
105
- _globals['_REJECTREQUEST']._serialized_start=3794
106
- _globals['_REJECTREQUEST']._serialized_end=3902
107
- _globals['_REJECTRESPONSE']._serialized_start=3904
108
- _globals['_REJECTRESPONSE']._serialized_end=3950
109
- _globals['_EXTENDLEASEREQUEST']._serialized_start=3953
110
- _globals['_EXTENDLEASEREQUEST']._serialized_end=4097
111
- _globals['_EXTENDLEASERESPONSE']._serialized_start=4099
112
- _globals['_EXTENDLEASERESPONSE']._serialized_end=4152
113
- _globals['_REPORTPROGRESSREQUEST']._serialized_start=4155
114
- _globals['_REPORTPROGRESSREQUEST']._serialized_end=4305
115
- _globals['_REPORTPROGRESSRESPONSE']._serialized_start=4307
116
- _globals['_REPORTPROGRESSRESPONSE']._serialized_end=4331
117
- _globals['_WORKERREGISTRATION']._serialized_start=4334
118
- _globals['_WORKERREGISTRATION']._serialized_end=4527
119
- _globals['_CREDITUPDATE']._serialized_start=4529
120
- _globals['_CREDITUPDATE']._serialized_end=4562
121
- _globals['_WORKERDRAIN']._serialized_start=4564
122
- _globals['_WORKERDRAIN']._serialized_end=4592
123
- _globals['_WORKERREGISTERED']._serialized_start=4594
124
- _globals['_WORKERREGISTERED']._serialized_end=4707
125
- _globals['_WORKREQUEST']._serialized_start=4710
126
- _globals['_WORKREQUEST']._serialized_end=5109
127
- _globals['_WORKRESULT']._serialized_start=5111
128
- _globals['_WORKRESULT']._serialized_end=5181
129
- _globals['_WORKRESPONSE']._serialized_start=5184
130
- _globals['_WORKRESPONSE']._serialized_end=5383
131
- _globals['_QUEUESERVICE']._serialized_start=5990
132
- _globals['_QUEUESERVICE']._serialized_end=6794
87
+ _globals['_GETQUEUEACTIVITYREQUEST']._serialized_start=2948
88
+ _globals['_GETQUEUEACTIVITYREQUEST']._serialized_end=3051
89
+ _globals['_GETQUEUEACTIVITYRESPONSE']._serialized_start=3053
90
+ _globals['_GETQUEUEACTIVITYRESPONSE']._serialized_end=3106
91
+ _globals['_RETRYTASKREQUEST']._serialized_start=3108
92
+ _globals['_RETRYTASKREQUEST']._serialized_end=3232
93
+ _globals['_RETRYTASKRESPONSE']._serialized_start=3234
94
+ _globals['_RETRYTASKRESPONSE']._serialized_end=3283
95
+ _globals['_CLAIMREQUEST']._serialized_start=3286
96
+ _globals['_CLAIMREQUEST']._serialized_end=3512
97
+ _globals['_CLAIMRESPONSE']._serialized_start=3514
98
+ _globals['_CLAIMRESPONSE']._serialized_end=3566
99
+ _globals['_LEASEREF']._serialized_start=3568
100
+ _globals['_LEASEREF']._serialized_end=3633
101
+ _globals['_ACKREQUEST']._serialized_start=3635
102
+ _globals['_ACKREQUEST']._serialized_end=3725
103
+ _globals['_ACKRESPONSE']._serialized_start=3727
104
+ _globals['_ACKRESPONSE']._serialized_end=3740
105
+ _globals['_NACKREQUEST']._serialized_start=3743
106
+ _globals['_NACKREQUEST']._serialized_end=3906
107
+ _globals['_NACKRESPONSE']._serialized_start=3908
108
+ _globals['_NACKRESPONSE']._serialized_end=3952
109
+ _globals['_REJECTREQUEST']._serialized_start=3954
110
+ _globals['_REJECTREQUEST']._serialized_end=4062
111
+ _globals['_REJECTRESPONSE']._serialized_start=4064
112
+ _globals['_REJECTRESPONSE']._serialized_end=4110
113
+ _globals['_EXTENDLEASEREQUEST']._serialized_start=4113
114
+ _globals['_EXTENDLEASEREQUEST']._serialized_end=4257
115
+ _globals['_EXTENDLEASERESPONSE']._serialized_start=4259
116
+ _globals['_EXTENDLEASERESPONSE']._serialized_end=4312
117
+ _globals['_REPORTPROGRESSREQUEST']._serialized_start=4315
118
+ _globals['_REPORTPROGRESSREQUEST']._serialized_end=4465
119
+ _globals['_REPORTPROGRESSRESPONSE']._serialized_start=4467
120
+ _globals['_REPORTPROGRESSRESPONSE']._serialized_end=4491
121
+ _globals['_WORKERREGISTRATION']._serialized_start=4494
122
+ _globals['_WORKERREGISTRATION']._serialized_end=4687
123
+ _globals['_CREDITUPDATE']._serialized_start=4689
124
+ _globals['_CREDITUPDATE']._serialized_end=4722
125
+ _globals['_WORKERDRAIN']._serialized_start=4724
126
+ _globals['_WORKERDRAIN']._serialized_end=4752
127
+ _globals['_WORKERREGISTERED']._serialized_start=4754
128
+ _globals['_WORKERREGISTERED']._serialized_end=4867
129
+ _globals['_WORKREQUEST']._serialized_start=4870
130
+ _globals['_WORKREQUEST']._serialized_end=5269
131
+ _globals['_WORKRESULT']._serialized_start=5271
132
+ _globals['_WORKRESULT']._serialized_end=5341
133
+ _globals['_WORKRESPONSE']._serialized_start=5344
134
+ _globals['_WORKRESPONSE']._serialized_end=5543
135
+ _globals['_QUEUESERVICE']._serialized_start=6150
136
+ _globals['_QUEUESERVICE']._serialized_end=7045
133
137
  # @@protoc_insertion_point(module_scope)
@@ -56,6 +56,11 @@ class QueueServiceStub(object):
56
56
  request_serializer=ringo__task__queue_dot___proto_dot_ringo_dot_v1_dot_queue__pb2.GetTaskRequest.SerializeToString,
57
57
  response_deserializer=ringo__task__queue_dot___proto_dot_ringo_dot_v1_dot_queue__pb2.GetTaskResponse.FromString,
58
58
  _registered_method=True)
59
+ self.GetQueueActivity = channel.unary_unary(
60
+ '/ringo.v1.QueueService/GetQueueActivity',
61
+ request_serializer=ringo__task__queue_dot___proto_dot_ringo_dot_v1_dot_queue__pb2.GetQueueActivityRequest.SerializeToString,
62
+ response_deserializer=ringo__task__queue_dot___proto_dot_ringo_dot_v1_dot_queue__pb2.GetQueueActivityResponse.FromString,
63
+ _registered_method=True)
59
64
  self.RetryTask = channel.unary_unary(
60
65
  '/ringo.v1.QueueService/RetryTask',
61
66
  request_serializer=ringo__task__queue_dot___proto_dot_ringo_dot_v1_dot_queue__pb2.RetryTaskRequest.SerializeToString,
@@ -126,6 +131,14 @@ class QueueServiceServicer(object):
126
131
  context.set_details('Method not implemented!')
127
132
  raise NotImplementedError('Method not implemented!')
128
133
 
134
+ def GetQueueActivity(self, request, context):
135
+ """GetQueueActivity returns a point-in-time queue/type-scope activity count.
136
+ It is read-only and does not seal the queue or promise durable completion.
137
+ """
138
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
139
+ context.set_details('Method not implemented!')
140
+ raise NotImplementedError('Method not implemented!')
141
+
129
142
  def RetryTask(self, request, context):
130
143
  """Missing associated documentation comment in .proto file."""
131
144
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
@@ -197,6 +210,11 @@ def add_QueueServiceServicer_to_server(servicer, server):
197
210
  request_deserializer=ringo__task__queue_dot___proto_dot_ringo_dot_v1_dot_queue__pb2.GetTaskRequest.FromString,
198
211
  response_serializer=ringo__task__queue_dot___proto_dot_ringo_dot_v1_dot_queue__pb2.GetTaskResponse.SerializeToString,
199
212
  ),
213
+ 'GetQueueActivity': grpc.unary_unary_rpc_method_handler(
214
+ servicer.GetQueueActivity,
215
+ request_deserializer=ringo__task__queue_dot___proto_dot_ringo_dot_v1_dot_queue__pb2.GetQueueActivityRequest.FromString,
216
+ response_serializer=ringo__task__queue_dot___proto_dot_ringo_dot_v1_dot_queue__pb2.GetQueueActivityResponse.SerializeToString,
217
+ ),
200
218
  'RetryTask': grpc.unary_unary_rpc_method_handler(
201
219
  servicer.RetryTask,
202
220
  request_deserializer=ringo__task__queue_dot___proto_dot_ringo_dot_v1_dot_queue__pb2.RetryTaskRequest.FromString,
@@ -357,6 +375,33 @@ class QueueService(object):
357
375
  metadata,
358
376
  _registered_method=True)
359
377
 
378
+ @staticmethod
379
+ def GetQueueActivity(request,
380
+ target,
381
+ options=(),
382
+ channel_credentials=None,
383
+ call_credentials=None,
384
+ insecure=False,
385
+ compression=None,
386
+ wait_for_ready=None,
387
+ timeout=None,
388
+ metadata=None):
389
+ return grpc.experimental.unary_unary(
390
+ request,
391
+ target,
392
+ '/ringo.v1.QueueService/GetQueueActivity',
393
+ ringo__task__queue_dot___proto_dot_ringo_dot_v1_dot_queue__pb2.GetQueueActivityRequest.SerializeToString,
394
+ ringo__task__queue_dot___proto_dot_ringo_dot_v1_dot_queue__pb2.GetQueueActivityResponse.FromString,
395
+ options,
396
+ channel_credentials,
397
+ insecure,
398
+ call_credentials,
399
+ compression,
400
+ wait_for_ready,
401
+ timeout,
402
+ metadata,
403
+ _registered_method=True)
404
+
360
405
  @staticmethod
361
406
  def RetryTask(request,
362
407
  target,
@@ -1,8 +1,8 @@
1
1
  """Release-line constants shared by runtime packaging checks."""
2
2
 
3
- SDK_VERSION = "0.1.0.dev1"
3
+ SDK_VERSION = "0.1.0.dev2"
4
4
  PROTOCOL_MAJOR = 1
5
- PROTOCOL_MINOR = 0
5
+ PROTOCOL_MINOR = 1
6
6
  SCHEMA_VERSION = 3
7
7
 
8
8
 
@@ -4,17 +4,17 @@
4
4
  "arch": "amd64",
5
5
  "filename": "ringo-task-queue-windows-amd64.exe",
6
6
  "os": "windows",
7
- "sha256": "c24105e131ddd8f2615739ebd4daf670313396e1a39e2f8c3316eb35c4dbd036",
8
- "size": 22855680
7
+ "sha256": "ad38397d8fe70fb4712f43b32d336e6ebb8550a552c9ab376da5f3785686571a",
8
+ "size": 22874624
9
9
  }
10
10
  ],
11
- "buildCommit": "bench",
11
+ "buildCommit": "38c81fd",
12
12
  "buildDate": "2026-03-01T00:00:00Z",
13
13
  "manifestVersion": 1,
14
14
  "name": "ringo-task-queue",
15
15
  "protocolMajor": 1,
16
- "protocolMinor": 0,
17
- "releaseManifestSha256": "c94782d799fae3995c49fecac7f4cb7ef65154c67351f587ad2841a5e59c2471",
16
+ "protocolMinor": 1,
17
+ "releaseManifestSha256": "23e6bb426c34fa417ca0921acfb9d57bbd726616f597894b40cef224fd469eb5",
18
18
  "schemaVersion": 3,
19
- "version": "0.1.0-dev.1"
19
+ "version": "0.1.0-dev.2"
20
20
  }
@@ -670,23 +670,36 @@ class TaskQueue:
670
670
  return EnqueueResult.from_proto(response.result)
671
671
 
672
672
  async def enqueue_many(self, specs: Iterable[TaskSpec]) -> BatchResult:
673
- """Enqueue a batch (max 1000), reporting every item individually."""
673
+ """Enqueue any number of tasks, auto-batching under the server limit.
674
+
675
+ The server enforces a hard limit of ``_MAX_ENQUEUE_BATCH`` (1000)
676
+ tasks per gRPC call. This method transparently splits larger
677
+ iterables into sequential sub-batches, preserving creation order,
678
+ and aggregates the per-item results into a single :class:`BatchResult`.
679
+
680
+ Fail-fast: if any sub-batch fails, the exception propagates and no
681
+ partial result is returned.
682
+ """
674
683
  specs = list(specs)
675
- if not specs:
676
- raise InvalidArgumentError("enqueue_many requires at least one TaskSpec")
677
- if len(specs) > _MAX_ENQUEUE_BATCH:
678
- raise InvalidArgumentError(
679
- f"enqueue_many accepts at most {_MAX_ENQUEUE_BATCH} tasks"
684
+ all_results: list[EnqueueResult] = []
685
+ total_created = 0
686
+ total_duplicates = 0
687
+
688
+ for start in range(0, len(specs), _MAX_ENQUEUE_BATCH):
689
+ chunk = specs[start : start + _MAX_ENQUEUE_BATCH]
690
+ request = queue_pb2.EnqueueManyRequest(
691
+ queue=self.name, tasks=[s.to_proto() for s in chunk]
680
692
  )
681
- request = queue_pb2.EnqueueManyRequest(
682
- queue=self.name, tasks=[s.to_proto() for s in specs]
683
- )
684
- request.context.CopyFrom(self._client._require_conn().request_context())
685
- response = await self._client._require_conn().call("EnqueueMany", request)
693
+ request.context.CopyFrom(self._client._require_conn().request_context())
694
+ response = await self._client._require_conn().call("EnqueueMany", request)
695
+ all_results.extend(EnqueueResult.from_proto(r) for r in response.results)
696
+ total_created += response.created_count
697
+ total_duplicates += response.duplicate_count
698
+
686
699
  return BatchResult(
687
- results=[EnqueueResult.from_proto(r) for r in response.results],
688
- created_count=response.created_count,
689
- duplicate_count=response.duplicate_count,
700
+ results=all_results,
701
+ created_count=total_created,
702
+ duplicate_count=total_duplicates,
690
703
  )
691
704
 
692
705
  # -- queries ------------------------------------------------------------
@@ -779,12 +792,32 @@ class TaskQueue:
779
792
  concurrency: int = 1,
780
793
  lease_duration: timedelta = timedelta(seconds=60),
781
794
  grace_period: timedelta = timedelta(seconds=30),
795
+ on_idle: Callable[[], Any] | None = None,
782
796
  ) -> "Worker":
783
- """Create a credit-controlled worker over the frozen Work stream."""
797
+ """Create a credit-controlled worker over the frozen Work stream.
798
+
799
+ ``on_idle`` is an optional zero-argument callable (sync or awaitable)
800
+ for bounded batch runs: once the worker has registered and sent its
801
+ initial credit, the SDK polls queue activity every 250 ms via the
802
+ read-only ``GetQueueActivity`` RPC scoped to this worker's
803
+ ``task_types``; after the activity count has been continuously zero
804
+ for at least 1 s the callback fires exactly once, inline on the
805
+ ``run()`` coroutine. A callback that returns normally leaves the
806
+ worker running (and never fires again); any exception it raises —
807
+ including ``SystemExit`` — propagates verbatim out of
808
+ ``await worker.run()`` without becoming a task NACK. Workers without
809
+ ``on_idle`` never send activity RPCs and stay compatible with
810
+ protocol minor 0 servers; ``on_idle`` requires minor >= 1 and raises
811
+ :class:`IncompatibleVersionError` from ``run()`` otherwise. Never
812
+ call ``worker.close()`` from inside the callback (it would wait on
813
+ the very coroutine executing it).
814
+ """
784
815
  from .worker import Worker
785
816
 
786
817
  if not callable(handler):
787
818
  raise InvalidArgumentError("handler must be callable")
819
+ if on_idle is not None and not callable(on_idle):
820
+ raise InvalidArgumentError("on_idle must be callable")
788
821
  if concurrency < 1 or concurrency > 2**32 - 1:
789
822
  raise InvalidArgumentError("concurrency must fit in a non-zero uint32")
790
823
  if lease_duration < timedelta(0):
@@ -798,6 +831,7 @@ class TaskQueue:
798
831
  concurrency=concurrency,
799
832
  lease_duration=lease_duration,
800
833
  grace_period=grace_period,
834
+ on_idle=on_idle,
801
835
  )
802
836
  self._client._register_worker(worker)
803
837
  return worker
@@ -18,19 +18,27 @@ import grpc
18
18
  from . import _pb
19
19
  from ._proto.ringo.v1 import queue_pb2
20
20
  from .errors import (
21
+ IncompatibleVersionError,
21
22
  LeaseLostError,
22
23
  PermanentTaskError,
23
- RingoError,
24
24
  RetryTaskError,
25
+ RingoError,
25
26
  UnavailableError,
26
27
  error_from_detail,
27
28
  map_rpc_error,
28
29
  )
29
30
  from .models import Task
30
31
 
31
-
32
32
  _MAX_ERROR_BYTES = 256 * 1024
33
33
 
34
+ #: Fixed on_idle monitor cadence (design §10.6). These are deliberately not
35
+ #: exposed as Worker parameters: the poll interval and the continuous-idle
36
+ #: quiet period are protocol-level constants of the idle-observation feature.
37
+ _IDLE_POLL_SECONDS = 0.25
38
+ _IDLE_QUIET_SECONDS = 1.0
39
+ #: GetQueueActivity was introduced in protocol minor 1.
40
+ _IDLE_MIN_PROTOCOL_MINOR = 1
41
+
34
42
 
35
43
  def _consume_task_exception(task: asyncio.Task[Any]) -> None:
36
44
  if not task.cancelled():
@@ -152,7 +160,8 @@ class Worker:
152
160
 
153
161
  ``run`` is intentionally a blocking coroutine: it remains active until
154
162
  ``close`` is called. The client registers workers and drains them before
155
- closing its channel.
163
+ closing its channel. When ``on_idle`` is configured, ``run`` additionally
164
+ observes queue activity and executes the callback inline at most once.
156
165
  """
157
166
 
158
167
  def __init__(
@@ -164,6 +173,7 @@ class Worker:
164
173
  concurrency: int,
165
174
  lease_duration: timedelta,
166
175
  grace_period: timedelta,
176
+ on_idle: Callable[[], Any] | None = None,
167
177
  ) -> None:
168
178
  if concurrency < 1:
169
179
  raise ValueError("concurrency must be >= 1")
@@ -175,6 +185,21 @@ class Worker:
175
185
  self._lease_duration = lease_duration
176
186
  self._grace_period = max(0.0, grace_period.total_seconds())
177
187
  self._worker_id = self._new_worker_id()
188
+ self._on_idle = on_idle
189
+ # on_idle monitor state (design §10.6). ``_idle_candidate`` arms only
190
+ # after WorkerRegistered plus the initial credit of the *current*
191
+ # session; every reset condition disarms it or clears the zero timer.
192
+ self._idle_candidate = False
193
+ self._idle_zero_since: float | None = None
194
+ self._idle_fired = False
195
+ #: Session token captured at WorkerRegistered + initial credit. The
196
+ #: candidate is only observable while the connection still carries
197
+ #: this token: a unary-triggered renegotiation rotates the token
198
+ #: without touching the Work stream and must disarm the monitor.
199
+ self._idle_session_token: str | None = None
200
+ #: Set when the on_idle callback raised: run() must re-raise verbatim
201
+ #: instead of counting it as a Work-stream reconnect failure.
202
+ self._idle_error: BaseException | None = None
178
203
 
179
204
  # close_started means no new stream may be opened, while force_cancel
180
205
  # is raised only after the graceful drain window expires. Existing
@@ -220,14 +245,34 @@ class Worker:
220
245
  self._run_started = True
221
246
  failures = 0
222
247
  try:
248
+ if self._on_idle is not None:
249
+ # GetQueueActivity arrived in protocol minor 1; fail fast
250
+ # instead of silently running without idle observation.
251
+ conn = self._client._require_conn()
252
+ if conn._session_minor < _IDLE_MIN_PROTOCOL_MINOR:
253
+ raise IncompatibleVersionError(
254
+ "on_idle requires a server speaking protocol minor"
255
+ f" >= {_IDLE_MIN_PROTOCOL_MINOR}; negotiated minor"
256
+ f" is {conn._session_minor}"
257
+ )
223
258
  while not self._close_started.is_set():
224
259
  try:
225
- await self._run_session()
260
+ await self._run_session_monitored()
226
261
  except asyncio.CancelledError:
227
262
  if not self._close_started.is_set():
228
263
  raise
229
264
  break
230
265
  except Exception as exc:
266
+ if self._idle_error is not None:
267
+ # An on_idle callback failure is not a transport
268
+ # error: it must not be retried, reconnected, or
269
+ # converted into a task NACK.
270
+ raise
271
+ if isinstance(exc, IncompatibleVersionError):
272
+ # A reconnect may have renegotiated a protocol
273
+ # downgrade that makes on_idle unservable; surface
274
+ # it instead of burning the reconnect budget.
275
+ raise
231
276
  self._stream_error = exc
232
277
  failures += 1
233
278
  if self._close_started.is_set():
@@ -259,6 +304,9 @@ class Worker:
259
304
  async with self._close_lock:
260
305
  if self._close_task is None:
261
306
  self._close_started.set()
307
+ self._idle_candidate = False
308
+ self._idle_zero_since = None
309
+ self._idle_session_token = None
262
310
  self._close_task = asyncio.create_task(
263
311
  self._close_impl(), name=f"ringo-close-{self._worker_id}"
264
312
  )
@@ -314,6 +362,10 @@ class Worker:
314
362
  await asyncio.gather(*tasks, return_exceptions=True)
315
363
 
316
364
  async def _cancel_assignments(self) -> None:
365
+ # Local assignments were reset, so the idle observation restarts too.
366
+ self._idle_candidate = False
367
+ self._idle_zero_since = None
368
+ self._idle_session_token = None
317
369
  assignments = list(self._inflight.values())
318
370
  self._inflight.clear()
319
371
  for assignment in assignments:
@@ -339,8 +391,156 @@ class Worker:
339
391
  if assignment.context is not None:
340
392
  assignment.context._cancel()
341
393
 
394
+ async def _run_session_monitored(self) -> None:
395
+ """Run one Work session, observing queue activity when on_idle is set.
396
+
397
+ Without ``on_idle`` this is exactly ``_run_session()``. With it, the
398
+ poll loop is executed inline by the ``run()`` coroutine itself (never
399
+ in a child task) so a callback exception — including ``SystemExit`` —
400
+ unwinds verbatim through ``await worker.run()``.
401
+ """
402
+ if self._on_idle is None:
403
+ await self._run_session()
404
+ return
405
+ session_task = asyncio.create_task(
406
+ self._run_session(), name="ringo-worker-session"
407
+ )
408
+ try:
409
+ while True:
410
+ done, _pending = await asyncio.wait(
411
+ (session_task,), timeout=_IDLE_POLL_SECONDS
412
+ )
413
+ if done:
414
+ # Propagate the session outcome (result or stream error).
415
+ return await session_task
416
+ if await self._idle_poll_once():
417
+ # Single-shot fired and returned normally: park on the
418
+ # session instead of waking every poll interval.
419
+ return await session_task
420
+ finally:
421
+ if not session_task.done():
422
+ session_task.cancel()
423
+ await asyncio.gather(session_task, return_exceptions=True)
424
+
425
+ async def _idle_poll_once(self) -> bool:
426
+ """One read-only, retry-safe activity observation tick.
427
+
428
+ Returns True exactly when the callback fired and returned normally.
429
+ """
430
+ callback = self._on_idle
431
+ if (
432
+ callback is None
433
+ or self._idle_fired
434
+ or not self._idle_candidate
435
+ or self._close_started.is_set()
436
+ or self._force_cancel.is_set()
437
+ ):
438
+ return False
439
+ # Local assignments make the queue non-idle for this worker.
440
+ if self._inflight:
441
+ self._idle_zero_since = None
442
+ return False
443
+ session = self._session_done
444
+ if session is None or session.is_set():
445
+ return False
446
+ # The observation is bound to the token captured at registration: a
447
+ # unary-triggered renegotiation rotates the token without restarting
448
+ # the Work stream. End this session so the run loop re-registers the
449
+ # stream under the fresh token instead of observing a stale session.
450
+ conn = self._client._require_conn()
451
+ if conn._session_token != self._idle_session_token:
452
+ self._end_stale_idle_session(session)
453
+ return False
454
+ request = queue_pb2.GetQueueActivityRequest(
455
+ queue=self._queue.name, task_types=self._task_types
456
+ )
457
+ try:
458
+ response = await conn.call(
459
+ "GetQueueActivity", request, retry_safe=True
460
+ )
461
+ except asyncio.CancelledError:
462
+ raise
463
+ except Exception:
464
+ # A failed observation restarts the quiet window; a later poll
465
+ # may succeed again without tearing the session down.
466
+ self._idle_zero_since = None
467
+ return False
468
+ # The session or its token may have changed while the query was in
469
+ # flight; a stale response must not advance or complete the window.
470
+ if (
471
+ not self._idle_candidate
472
+ or self._session_done is not session
473
+ or session.is_set()
474
+ ):
475
+ self._idle_zero_since = None
476
+ return False
477
+ if self._client._require_conn()._session_token != self._idle_session_token:
478
+ self._end_stale_idle_session(session)
479
+ return False
480
+ if response.active_task_count > 0:
481
+ self._idle_zero_since = None
482
+ return False
483
+ now = asyncio.get_running_loop().time()
484
+ if self._idle_zero_since is None:
485
+ self._idle_zero_since = now
486
+ return False
487
+ if now - self._idle_zero_since < _IDLE_QUIET_SECONDS:
488
+ return False
489
+ # Final atomic gate: no await separates these checks from marking
490
+ # fired and invoking the callback, so an assignment landing in a
491
+ # query in-flight window cannot produce a false trigger.
492
+ if (
493
+ self._inflight
494
+ or self._close_started.is_set()
495
+ or self._force_cancel.is_set()
496
+ ):
497
+ self._idle_zero_since = None
498
+ return False
499
+ # Single-shot: mark before invoking so the callback can never
500
+ # re-enter the monitor, and so a normal return never fires twice.
501
+ self._idle_fired = True
502
+ try:
503
+ result = callback()
504
+ if inspect.isawaitable(result):
505
+ await result
506
+ except BaseException as exc:
507
+ # Tag callback failures so run() propagates them verbatim
508
+ # instead of feeding them to the reconnect loop.
509
+ self._idle_error = exc
510
+ raise
511
+ return True
512
+
513
+ def _end_stale_idle_session(self, session: asyncio.Event) -> None:
514
+ """End the current Work session after a token rotation.
515
+
516
+ Setting ``session_done`` is idempotent and is observed as a clean
517
+ stream end: ``_run_session`` returns without a stream error, the run
518
+ loop reconnects, and the next session re-registers (and re-arms the
519
+ idle candidate) under the fresh token. It is neither a callback
520
+ failure nor a reconnect-worthy stream error.
521
+ """
522
+ self._idle_candidate = False
523
+ self._idle_zero_since = None
524
+ session.set()
525
+
342
526
  async def _run_session(self) -> None:
343
527
  conn = self._client._require_conn()
528
+ # A new session invalidates any in-flight idle observation.
529
+ self._idle_candidate = False
530
+ self._idle_zero_since = None
531
+ self._idle_session_token = None
532
+ if (
533
+ self._on_idle is not None
534
+ and conn._session_minor < _IDLE_MIN_PROTOCOL_MINOR
535
+ ):
536
+ # A reconnect may have renegotiated a downgrade to minor 0.
537
+ # Fail fast before opening the Work stream; run() surfaces this
538
+ # verbatim instead of counting it as a reconnect failure.
539
+ raise IncompatibleVersionError(
540
+ "on_idle requires a server speaking protocol minor"
541
+ f" >= {_IDLE_MIN_PROTOCOL_MINOR}; negotiated minor"
542
+ f" is {conn._session_minor}"
543
+ )
344
544
  reg = queue_pb2.WorkerRegistration(
345
545
  queue=self._queue.name,
346
546
  worker_id=self._worker_id,
@@ -372,6 +572,15 @@ class Worker:
372
572
  return
373
573
  # Initial credit is sent only after WorkerRegistered was observed.
374
574
  await self._send_credit(self._concurrency)
575
+ if self._on_idle is not None and not self._close_started.is_set():
576
+ # Eligible only from the first/current WorkerRegistered plus
577
+ # a successful initial credit of this session. The candidate
578
+ # is bound to the token this stream was registered with: a
579
+ # later unary renegotiation that rotates the token disarms
580
+ # the monitor until the next session.
581
+ self._idle_session_token = reg.context.session_token
582
+ self._idle_candidate = True
583
+ self._idle_zero_since = None
375
584
  await self._wait_event_or_session(self._session_done)
376
585
  if self._stream_error is not None and not self._close_started.is_set():
377
586
  raise self._stream_error
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ringo-task-queue
3
- Version: 0.1.0.dev1
3
+ Version: 0.1.0.dev2
4
4
  Summary: Python asyncio SDK for Ringo Task Queue with a bundled offline Go daemon
5
5
  Author: Ringo Task Queue contributors
6
6
  License-Expression: MIT
@@ -217,7 +217,7 @@ batch = await queue.enqueue_many(
217
217
  print(batch.created_count, batch.duplicate_count)
218
218
  ```
219
219
 
220
- 每批 1–1,000 条,`batch.results` 保留逐项结果。
220
+ `enqueue_many` 接受任意数量任务,SDK 自动按服务端单批上限 1,000 条切分并顺序发送,最终聚合为单个 `BatchResult`;`batch.results` 保留逐项结果。若任一批次失败,异常直接抛出,不返回部分结果。
221
221
 
222
222
  ## 查询和手工重试
223
223
 
@@ -234,7 +234,9 @@ reopened = await queue.retry_by_id(result.task_id)
234
234
 
235
235
  状态包括 `SCHEDULED`、`READY`、`LEASED`、`SUCCEEDED`、`DEAD` 和 `CANCELLED`。`Task` 还提供 attempt 历史、最后错误、进度和当前 lease 摘要。手工 retry 保留历史和永久去重关系。
236
236
 
237
- ## Worker
237
+ ## Worker(推荐)
238
+
239
+ 处理队列任务推荐直接使用 `Worker`,而不是下面的手工 Claim:Worker 自动管理注册、credit、lease 续租、并发和优雅关闭。
238
240
 
239
241
  ```python
240
242
  from datetime import timedelta
@@ -260,7 +262,7 @@ worker = queue.worker(
260
262
  await worker.run()
261
263
  ```
262
264
 
263
- `run()` 一直运行到其他协程调用 `await worker.close()`,并且只能调用一次。通常用 `asyncio.create_task(worker.run())` 启动。
265
+ `run()` 一直运行到其他协程调用 `await worker.close()`,并且只能调用一次。常驻消费时用 `asyncio.create_task(worker.run())` 启动;已知有限批次(见下)直接 `await worker.run()`。
264
266
 
265
267
  Handler 映射:
266
268
 
@@ -276,8 +278,60 @@ Worker 持有 lease token,自动续租并严格控制并发。`TaskContext`
276
278
 
277
279
  这是至少一次系统:handler 的外部副作用必须使用 `unique_key` 或任务 ID 实现幂等。
278
280
 
281
+ ### 有限批次与 `on_idle`(PyPI 推荐范式)
282
+
283
+ 已知有限批次(例如"把这批 seed 跑完就退出")的推荐写法:**先在 `run()` 之前提交幂等 seed**,再给 Worker 配置一次性的 `on_idle` 回调,并**直接 `await worker.run()`**:
284
+
285
+ ```python
286
+ import asyncio
287
+ import sys
288
+
289
+ from ringo_task_queue import Ringo
290
+
291
+
292
+ async def main() -> None:
293
+ async with Ringo.local("./data/ringo") as client:
294
+ queue = client.queue("email")
295
+
296
+ # 1. 先提交幂等 seed(run() 之前 enqueue)。
297
+ for user_id in (101, 102, 103):
298
+ await queue.enqueue(
299
+ unique_key=f"welcome:{user_id}",
300
+ task_type="send-email",
301
+ payload={"user_id": user_id},
302
+ )
303
+
304
+ async def handle(task, ctx) -> None:
305
+ await send_welcome(task.payload["user_id"])
306
+
307
+ # 2. 队列在该 Worker 的 task type 范围内连续空闲满 1 秒后触发一次。
308
+ worker = queue.worker(
309
+ handle,
310
+ task_types=["send-email"],
311
+ concurrency=4,
312
+ on_idle=lambda: sys.exit(0),
313
+ )
314
+
315
+ # 3. 前台直接 await run();on_idle 触发后整个批次随之结束。
316
+ await worker.run()
317
+
318
+
319
+ asyncio.run(main())
320
+ ```
321
+
322
+ 语义与限制(务必阅读):
323
+
324
+ - **固定参数**:SDK 以 250 ms 间隔轮询、连续空闲满 1 秒触发一次;这两个值是协议级常量,不提供配置参数。
325
+ - **单次触发**:回调最多触发一次。正常返回后 Worker 继续常驻运行且不再触发;要结束进程请在回调里退出(如 `sys.exit(0)`),异常会原样从 `await worker.run()` 传播。
326
+ - **type scope**:活动数只统计该 Worker `task_types` 范围内的任务(`SCHEDULED`/`READY`/`LEASED` 都算活动),不影响队列里其他类型的任务。
327
+ - **开放队列竞态**:空闲观察只是开放队列上的观测快照,不是持久完成判定。回调**正常返回**且 Worker 保持常驻时,观察之后提交的新任务仍会被正常消费;但如果回调直接退出进程(如 `sys.exit(0)`),观测之后、退出之前竞态提交的任务不会被本 Worker 处理,可能留给其他 Worker 或下一次运行。因此 `sys.exit(0)` 范式只适合生产者已经停止的有限批次。需要严格分布式完成判定时,必须另行设计 queue seal/generation。
328
+ - **不要在回调里 `close()`**:`on_idle` 由 `worker.run()` 协程内联执行,在回调里等待同一 Worker/client 的关闭会造成自等待。外层资源作用域(如上面的 `async with`)负责清理。
329
+ - **兼容性**:不带 `on_idle` 的 Worker 从不发送活动查询 RPC,与协议 minor 0 的旧 server 完全兼容;配置 `on_idle` 需要 minor ≥ 1 的 server,旧 server 会在 `run()` 快速抛出 `IncompatibleVersionError`。
330
+
279
331
  ## 手工 Claim
280
332
 
333
+ > 常规消费任务优先使用上面推荐的 `Worker`;手工 Claim 适用于需要自行控制 claim/ACK 时序的高级场景。
334
+
281
335
  ```python
282
336
  from datetime import timedelta
283
337
 
@@ -367,14 +421,14 @@ except RingoError as exc:
367
421
 
368
422
  | 项目 | 默认值或限制 |
369
423
  |---|---|
370
- | 协议 | 1.0 |
424
+ | 协议 | 1.1 |
371
425
  | schema | 3 |
372
426
  | lease | 60 秒 |
373
427
  | worker concurrency | 1 |
374
428
  | graceful shutdown | 30 秒 |
375
429
  | retry attempts | 默认 3,最大 32 |
376
430
  | retry | 指数退避,1 秒到 60 秒,multiplier 2,jitter 0.2 |
377
- | batch | 最大 1,000 |
431
+ | batch | SDK 自动分批,单批最大 1,000 |
378
432
  | payload | 最大 1 MiB UTF-8 JSON |
379
433
  | error text | 最大 256 KiB UTF-8 |
380
434
  | daemon 自动重启 | 最多 3 次 |
@@ -0,0 +1,18 @@
1
+ ringo_task_queue/__init__.py,sha256=MUeo1atWuaoNITczk6hDs4zYLI18IEpkVBHOE3wGhFc,1381
2
+ ringo_task_queue/_pb.py,sha256=gA8HMCx9ZXEMB-ca6me8CYXdRLLPzUXVIz63Q4bz75I,5683
3
+ ringo_task_queue/_version.py,sha256=ZzMLs6sHjRJhsqQlzaUywRpm7l_Fnt6prJ6UH1e1vAY,446
4
+ ringo_task_queue/binary.py,sha256=lJtFz_t5BuxDV4dMAqQDpP3mhTvJlnPBGnaiB0Z9D04,9526
5
+ ringo_task_queue/client.py,sha256=c7tCI5q2P0EQc_7RZcofHQHewBPVXGwtiLmKk_KUCsI,35380
6
+ ringo_task_queue/daemon.py,sha256=YS8otZpD9hqKeASb2S8ZWLCWzQj6-FYUb-grmYSnrIs,19849
7
+ ringo_task_queue/errors.py,sha256=UCPl1GJSlHzvGPO5WOmkYwLBqZj8Aozlz7sChAXR8pw,4719
8
+ ringo_task_queue/models.py,sha256=MEXh2JKgCbf3vo0EmnjJ_TscwabaW5Yd9i98LSPIrnk,11691
9
+ ringo_task_queue/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ ringo_task_queue/worker.py,sha256=lminZk8MQgOE2Gf6-8cNymaNb4iXpmtLERSaMxgMDqg,40317
11
+ ringo_task_queue/_proto/ringo/v1/queue_pb2.py,sha256=EyddzrHyXbndhxHm_EMlzLXFVMJGQNZEWgV665NM6IQ,18691
12
+ ringo_task_queue/_proto/ringo/v1/queue_pb2_grpc.py,sha256=b_F-9z6npDpHs3VdIJAhYfPKF6e3pJYSQTonripfWLA,28290
13
+ ringo_task_queue/bin/manifest.json,sha256=VXBi2vZJbqz6Cn-nl8Tp0DO402tHIEjwCR5qm-WlNsc,576
14
+ ringo_task_queue/bin/ringo-task-queue-windows-amd64.exe,sha256=rTg5fY_nD7RxL0OzLTNubruFUKVSyas3baXzeFaGVxo,22874624
15
+ ringo_task_queue-0.1.0.dev2.dist-info/METADATA,sha256=jrL95c9BbnhlnFYpq682KHt2DQ76xGF7nCNo1FIxXhY,16957
16
+ ringo_task_queue-0.1.0.dev2.dist-info/WHEEL,sha256=0nQjyt02uAQbhbYKWZzlDb_ZXUmJUwgypQJ-m16yWKo,94
17
+ ringo_task_queue-0.1.0.dev2.dist-info/licenses/LICENSE,sha256=yK3nnJz_bbOAPlcJqAooYcvecNJnBH9miT_X8Qrerv4,1086
18
+ ringo_task_queue-0.1.0.dev2.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- ringo_task_queue/__init__.py,sha256=MUeo1atWuaoNITczk6hDs4zYLI18IEpkVBHOE3wGhFc,1381
2
- ringo_task_queue/_pb.py,sha256=gA8HMCx9ZXEMB-ca6me8CYXdRLLPzUXVIz63Q4bz75I,5683
3
- ringo_task_queue/_version.py,sha256=mi2kCx2g3PrLd5Vs37riqprlTm5cocdQfVc1vlWyCe4,446
4
- ringo_task_queue/binary.py,sha256=lJtFz_t5BuxDV4dMAqQDpP3mhTvJlnPBGnaiB0Z9D04,9526
5
- ringo_task_queue/client.py,sha256=GT-JiCMshtf_SFUFvjU_ayi7C0JyuQYOeLrmwISoFLc,33570
6
- ringo_task_queue/daemon.py,sha256=YS8otZpD9hqKeASb2S8ZWLCWzQj6-FYUb-grmYSnrIs,19849
7
- ringo_task_queue/errors.py,sha256=UCPl1GJSlHzvGPO5WOmkYwLBqZj8Aozlz7sChAXR8pw,4719
8
- ringo_task_queue/models.py,sha256=MEXh2JKgCbf3vo0EmnjJ_TscwabaW5Yd9i98LSPIrnk,11691
9
- ringo_task_queue/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- ringo_task_queue/worker.py,sha256=LD-J9XnQBxJWC2xvVi4tCAzms-O7wfkflSnoEFZXwnM,30366
11
- ringo_task_queue/_proto/ringo/v1/queue_pb2.py,sha256=Z4S0mNwPerMshRr7DUooj9oeecbaYG4JUpMJJlwVb0o,18074
12
- ringo_task_queue/_proto/ringo/v1/queue_pb2_grpc.py,sha256=eKtdXhZk3BP1I9IaYQlEgUF_K2WZLzBuIq7koWLhQ00,26066
13
- ringo_task_queue/bin/manifest.json,sha256=LfSz8o5TEU1ZEeHJ02hgD3i6-yXz6jAeI3ceLZMIB7Y,574
14
- ringo_task_queue/bin/ringo-task-queue-windows-amd64.exe,sha256=wkEF4THd2PJhVznr1Nr2cDEzluGjni-MMxbrNcTb0DY,22855680
15
- ringo_task_queue-0.1.0.dev1.dist-info/METADATA,sha256=OuPm63uROxIrdFMeW8qgxSMTd6UnYbCfTcz2TuUSrVc,13515
16
- ringo_task_queue-0.1.0.dev1.dist-info/WHEEL,sha256=0nQjyt02uAQbhbYKWZzlDb_ZXUmJUwgypQJ-m16yWKo,94
17
- ringo_task_queue-0.1.0.dev1.dist-info/licenses/LICENSE,sha256=yK3nnJz_bbOAPlcJqAooYcvecNJnBH9miT_X8Qrerv4,1086
18
- ringo_task_queue-0.1.0.dev1.dist-info/RECORD,,