github.com/wfusion/gofusion@v1.1.14/common/infra/asynq/pkg/base/base.go (about) 1 // Copyright 2020 Kentaro Hibino. All rights reserved. 2 // Use of this source code is governed by a MIT license 3 // that can be found in the LICENSE file. 4 5 // Package base defines foundational types and constants used in asynq package. 6 package base 7 8 import ( 9 "context" 10 "crypto/md5" 11 "encoding/hex" 12 "fmt" 13 "strings" 14 "sync" 15 "time" 16 17 "github.com/redis/go-redis/v9" 18 "google.golang.org/protobuf/proto" 19 "google.golang.org/protobuf/types/known/timestamppb" 20 21 "github.com/wfusion/gofusion/common/infra/asynq/pkg/errors" 22 "github.com/wfusion/gofusion/common/infra/asynq/pkg/timeutil" 23 24 pb "github.com/wfusion/gofusion/common/infra/asynq/pkg/proto" 25 ) 26 27 // Version of asynq library and CLI. 28 const Version = "0.24.1" 29 30 // DefaultQueueName is the queue name used if none are specified by user. 31 const DefaultQueueName = "default" 32 33 // DefaultQueue is the redis key for the default queue. 34 var DefaultQueue = PendingKey(DefaultQueueName) 35 36 // Global Redis keys. 37 const ( 38 AllServers = "asynq:servers" // ZSET 39 AllWorkers = "asynq:workers" // ZSET 40 AllSchedulers = "asynq:schedulers" // ZSET 41 AllQueues = "asynq:queues" // SET 42 CancelChannel = "asynq:cancel" // PubSub channel 43 ) 44 45 // TaskState denotes the state of a task. 46 type TaskState int 47 48 const ( 49 TaskStateActive TaskState = iota + 1 50 TaskStatePending 51 TaskStateScheduled 52 TaskStateRetry 53 TaskStateArchived 54 TaskStateCompleted 55 TaskStateAggregating // describes a state where task is waiting in a group to be aggregated 56 ) 57 58 func (s TaskState) String() string { 59 switch s { 60 case TaskStateActive: 61 return "active" 62 case TaskStatePending: 63 return "pending" 64 case TaskStateScheduled: 65 return "scheduled" 66 case TaskStateRetry: 67 return "retry" 68 case TaskStateArchived: 69 return "archived" 70 case TaskStateCompleted: 71 return "completed" 72 case TaskStateAggregating: 73 return "aggregating" 74 } 75 panic(fmt.Sprintf("internal error: unknown task state %d", s)) 76 } 77 78 func TaskStateFromString(s string) (TaskState, error) { 79 switch s { 80 case "active": 81 return TaskStateActive, nil 82 case "pending": 83 return TaskStatePending, nil 84 case "scheduled": 85 return TaskStateScheduled, nil 86 case "retry": 87 return TaskStateRetry, nil 88 case "archived": 89 return TaskStateArchived, nil 90 case "completed": 91 return TaskStateCompleted, nil 92 case "aggregating": 93 return TaskStateAggregating, nil 94 } 95 return 0, errors.E(errors.FailedPrecondition, fmt.Sprintf("%q is not supported task state", s)) 96 } 97 98 // ValidateQueueName validates a given qname to be used as a queue name. 99 // Returns nil if valid, otherwise returns non-nil error. 100 func ValidateQueueName(qname string) error { 101 if len(strings.TrimSpace(qname)) == 0 { 102 return fmt.Errorf("queue name must contain one or more characters") 103 } 104 return nil 105 } 106 107 // QueueKeyPrefix returns a prefix for all keys in the given queue. 108 func QueueKeyPrefix(qname string) string { 109 return fmt.Sprintf("asynq:{%s}:", qname) 110 } 111 112 // TaskKeyPrefix returns a prefix for task key. 113 func TaskKeyPrefix(qname string) string { 114 return fmt.Sprintf("%st:", QueueKeyPrefix(qname)) 115 } 116 117 // TaskKey returns a redis key for the given task message. 118 func TaskKey(qname, id string) string { 119 return fmt.Sprintf("%s%s", TaskKeyPrefix(qname), id) 120 } 121 122 // PendingKey returns a redis key for the given queue name. 123 func PendingKey(qname string) string { 124 return fmt.Sprintf("%spending", QueueKeyPrefix(qname)) 125 } 126 127 // ActiveKey returns a redis key for the active tasks. 128 func ActiveKey(qname string) string { 129 return fmt.Sprintf("%sactive", QueueKeyPrefix(qname)) 130 } 131 132 // ScheduledKey returns a redis key for the scheduled tasks. 133 func ScheduledKey(qname string) string { 134 return fmt.Sprintf("%sscheduled", QueueKeyPrefix(qname)) 135 } 136 137 // RetryKey returns a redis key for the retry tasks. 138 func RetryKey(qname string) string { 139 return fmt.Sprintf("%sretry", QueueKeyPrefix(qname)) 140 } 141 142 // ArchivedKey returns a redis key for the archived tasks. 143 func ArchivedKey(qname string) string { 144 return fmt.Sprintf("%sarchived", QueueKeyPrefix(qname)) 145 } 146 147 // LeaseKey returns a redis key for the lease. 148 func LeaseKey(qname string) string { 149 return fmt.Sprintf("%slease", QueueKeyPrefix(qname)) 150 } 151 152 func CompletedKey(qname string) string { 153 return fmt.Sprintf("%scompleted", QueueKeyPrefix(qname)) 154 } 155 156 // PausedKey returns a redis key to indicate that the given queue is paused. 157 func PausedKey(qname string) string { 158 return fmt.Sprintf("%spaused", QueueKeyPrefix(qname)) 159 } 160 161 // ProcessedTotalKey returns a redis key for total processed count for the given queue. 162 func ProcessedTotalKey(qname string) string { 163 return fmt.Sprintf("%sprocessed", QueueKeyPrefix(qname)) 164 } 165 166 // FailedTotalKey returns a redis key for total failure count for the given queue. 167 func FailedTotalKey(qname string) string { 168 return fmt.Sprintf("%sfailed", QueueKeyPrefix(qname)) 169 } 170 171 // ProcessedKey returns a redis key for processed count for the given day for the queue. 172 func ProcessedKey(qname string, t time.Time) string { 173 return fmt.Sprintf("%sprocessed:%s", QueueKeyPrefix(qname), t.UTC().Format("2006-01-02")) 174 } 175 176 // FailedKey returns a redis key for failure count for the given day for the queue. 177 func FailedKey(qname string, t time.Time) string { 178 return fmt.Sprintf("%sfailed:%s", QueueKeyPrefix(qname), t.UTC().Format("2006-01-02")) 179 } 180 181 // ServerInfoKey returns a redis key for process info. 182 func ServerInfoKey(hostname string, pid int, serverID string) string { 183 return fmt.Sprintf("asynq:servers:{%s:%d:%s}", hostname, pid, serverID) 184 } 185 186 // WorkersKey returns a redis key for the workers given hostname, pid, and server ID. 187 func WorkersKey(hostname string, pid int, serverID string) string { 188 return fmt.Sprintf("asynq:workers:{%s:%d:%s}", hostname, pid, serverID) 189 } 190 191 // SchedulerEntriesKey returns a redis key for the scheduler entries given scheduler ID. 192 func SchedulerEntriesKey(schedulerID string) string { 193 return fmt.Sprintf("asynq:schedulers:{%s}", schedulerID) 194 } 195 196 // SchedulerHistoryKey returns a redis key for the scheduler's history for the given entry. 197 func SchedulerHistoryKey(entryID string) string { 198 return fmt.Sprintf("asynq:scheduler_history:%s", entryID) 199 } 200 201 // UniqueKey returns a redis key with the given type, payload, and queue name. 202 func UniqueKey(qname, tasktype string, payload []byte) string { 203 if payload == nil { 204 return fmt.Sprintf("%sunique:%s:", QueueKeyPrefix(qname), tasktype) 205 } 206 checksum := md5.Sum(payload) 207 return fmt.Sprintf("%sunique:%s:%s", QueueKeyPrefix(qname), tasktype, hex.EncodeToString(checksum[:])) 208 } 209 210 // GroupKeyPrefix returns a prefix for group key. 211 func GroupKeyPrefix(qname string) string { 212 return fmt.Sprintf("%sg:", QueueKeyPrefix(qname)) 213 } 214 215 // GroupKey returns a redis key used to group tasks belong in the same group. 216 func GroupKey(qname, gkey string) string { 217 return fmt.Sprintf("%s%s", GroupKeyPrefix(qname), gkey) 218 } 219 220 // AggregationSetKey returns a redis key used for an aggregation set. 221 func AggregationSetKey(qname, gname, setID string) string { 222 return fmt.Sprintf("%s:%s", GroupKey(qname, gname), setID) 223 } 224 225 // AllGroups return a redis key used to store all group keys used in a given queue. 226 func AllGroups(qname string) string { 227 return fmt.Sprintf("%sgroups", QueueKeyPrefix(qname)) 228 } 229 230 // AllAggregationSets returns a redis key used to store all aggregation sets (set of tasks staged to be aggregated) 231 // in a given queue. 232 func AllAggregationSets(qname string) string { 233 return fmt.Sprintf("%saggregation_sets", QueueKeyPrefix(qname)) 234 } 235 236 // TaskMessage is the internal representation of a task with additional metadata fields. 237 // Serialized data of this type gets written to redis. 238 type TaskMessage struct { 239 // Type indicates the kind of the task to be performed. 240 Type string 241 242 // Payload holds data needed to process the task. 243 Payload []byte 244 245 // ID is a unique identifier for each task. 246 ID string 247 248 // Queue is a name this message should be enqueued to. 249 Queue string 250 251 // Retry is the max number of retry for this task. 252 Retry int 253 254 // Retried is the number of times we've retried this task so far. 255 Retried int 256 257 // ErrorMsg holds the error message from the last failure. 258 ErrorMsg string 259 260 // Time of last failure in Unix time, 261 // the number of seconds elapsed since January 1, 1970 UTC. 262 // 263 // Use zero to indicate no last failure 264 LastFailedAt int64 265 266 // Timeout specifies timeout in seconds. 267 // If task processing doesn't complete within the timeout, the task will be retried 268 // if retry count is remaining. Otherwise it will be moved to the archive. 269 // 270 // Use zero to indicate no timeout. 271 Timeout int64 272 273 // Deadline specifies the deadline for the task in Unix time, 274 // the number of seconds elapsed since January 1, 1970 UTC. 275 // If task processing doesn't complete before the deadline, the task will be retried 276 // if retry count is remaining. Otherwise it will be moved to the archive. 277 // 278 // Use zero to indicate no deadline. 279 Deadline int64 280 281 // UniqueKey holds the redis key used for uniqueness lock for this task. 282 // 283 // Empty string indicates that no uniqueness lock was used. 284 UniqueKey string 285 286 // GroupKey holds the group key used for task aggregation. 287 // 288 // Empty string indicates no aggregation is used for this task. 289 GroupKey string 290 291 // Retention specifies the number of seconds the task should be retained after completion. 292 Retention int64 293 294 // CompletedAt is the time the task was processed successfully in Unix time, 295 // the number of seconds elapsed since January 1, 1970 UTC. 296 // 297 // Use zero to indicate no value. 298 CompletedAt int64 299 } 300 301 // EncodeMessage marshals the given task message and returns an encoded bytes. 302 func EncodeMessage(msg *TaskMessage) ([]byte, error) { 303 if msg == nil { 304 return nil, fmt.Errorf("cannot encode nil message") 305 } 306 return proto.Marshal(&pb.TaskMessage{ 307 Type: msg.Type, 308 Payload: msg.Payload, 309 Id: msg.ID, 310 Queue: msg.Queue, 311 Retry: int32(msg.Retry), 312 Retried: int32(msg.Retried), 313 ErrorMsg: msg.ErrorMsg, 314 LastFailedAt: msg.LastFailedAt, 315 Timeout: msg.Timeout, 316 Deadline: msg.Deadline, 317 UniqueKey: msg.UniqueKey, 318 GroupKey: msg.GroupKey, 319 Retention: msg.Retention, 320 CompletedAt: msg.CompletedAt, 321 }) 322 } 323 324 // DecodeMessage unmarshals the given bytes and returns a decoded task message. 325 func DecodeMessage(data []byte) (*TaskMessage, error) { 326 var pbmsg pb.TaskMessage 327 if err := proto.Unmarshal(data, &pbmsg); err != nil { 328 return nil, err 329 } 330 return &TaskMessage{ 331 Type: pbmsg.GetType(), 332 Payload: pbmsg.GetPayload(), 333 ID: pbmsg.GetId(), 334 Queue: pbmsg.GetQueue(), 335 Retry: int(pbmsg.GetRetry()), 336 Retried: int(pbmsg.GetRetried()), 337 ErrorMsg: pbmsg.GetErrorMsg(), 338 LastFailedAt: pbmsg.GetLastFailedAt(), 339 Timeout: pbmsg.GetTimeout(), 340 Deadline: pbmsg.GetDeadline(), 341 UniqueKey: pbmsg.GetUniqueKey(), 342 GroupKey: pbmsg.GetGroupKey(), 343 Retention: pbmsg.GetRetention(), 344 CompletedAt: pbmsg.GetCompletedAt(), 345 }, nil 346 } 347 348 // TaskInfo describes a task message and its metadata. 349 type TaskInfo struct { 350 Message *TaskMessage 351 State TaskState 352 NextProcessAt time.Time 353 Result []byte 354 } 355 356 // Z represents sorted set member. 357 type Z struct { 358 Message *TaskMessage 359 Score int64 360 } 361 362 // ServerInfo holds information about a running server. 363 type ServerInfo struct { 364 Host string 365 PID int 366 ServerID string 367 Concurrency int 368 Queues map[string]int 369 StrictPriority bool 370 Status string 371 Started time.Time 372 ActiveWorkerCount int 373 } 374 375 // EncodeServerInfo marshals the given ServerInfo and returns the encoded bytes. 376 func EncodeServerInfo(info *ServerInfo) ([]byte, error) { 377 if info == nil { 378 return nil, fmt.Errorf("cannot encode nil server info") 379 } 380 queues := make(map[string]int32) 381 for q, p := range info.Queues { 382 queues[q] = int32(p) 383 } 384 started := timestamppb.New(info.Started) 385 if err := started.CheckValid(); err != nil { 386 return nil, err 387 } 388 return proto.Marshal(&pb.ServerInfo{ 389 Host: info.Host, 390 Pid: int32(info.PID), 391 ServerId: info.ServerID, 392 Concurrency: int32(info.Concurrency), 393 Queues: queues, 394 StrictPriority: info.StrictPriority, 395 Status: info.Status, 396 StartTime: started, 397 ActiveWorkerCount: int32(info.ActiveWorkerCount), 398 }) 399 } 400 401 // DecodeServerInfo decodes the given bytes into ServerInfo. 402 func DecodeServerInfo(b []byte) (*ServerInfo, error) { 403 var pbmsg pb.ServerInfo 404 if err := proto.Unmarshal(b, &pbmsg); err != nil { 405 return nil, err 406 } 407 queues := make(map[string]int) 408 for q, p := range pbmsg.GetQueues() { 409 queues[q] = int(p) 410 } 411 startTime := pbmsg.GetStartTime().AsTime() 412 if err := pbmsg.GetStartTime().CheckValid(); err != nil { 413 return nil, err 414 } 415 return &ServerInfo{ 416 Host: pbmsg.GetHost(), 417 PID: int(pbmsg.GetPid()), 418 ServerID: pbmsg.GetServerId(), 419 Concurrency: int(pbmsg.GetConcurrency()), 420 Queues: queues, 421 StrictPriority: pbmsg.GetStrictPriority(), 422 Status: pbmsg.GetStatus(), 423 Started: startTime, 424 ActiveWorkerCount: int(pbmsg.GetActiveWorkerCount()), 425 }, nil 426 } 427 428 // WorkerInfo holds information about a running worker. 429 type WorkerInfo struct { 430 Host string 431 PID int 432 ServerID string 433 ID string 434 Type string 435 Payload []byte 436 Queue string 437 Started time.Time 438 Deadline time.Time 439 } 440 441 // EncodeWorkerInfo marshals the given WorkerInfo and returns the encoded bytes. 442 func EncodeWorkerInfo(info *WorkerInfo) ([]byte, error) { 443 if info == nil { 444 return nil, fmt.Errorf("cannot encode nil worker info") 445 } 446 startTime := timestamppb.New(info.Started) 447 if err := startTime.CheckValid(); err != nil { 448 return nil, err 449 } 450 deadline := timestamppb.New(info.Deadline) 451 if err := deadline.CheckValid(); err != nil { 452 return nil, err 453 } 454 return proto.Marshal(&pb.WorkerInfo{ 455 Host: info.Host, 456 Pid: int32(info.PID), 457 ServerId: info.ServerID, 458 TaskId: info.ID, 459 TaskType: info.Type, 460 TaskPayload: info.Payload, 461 Queue: info.Queue, 462 StartTime: startTime, 463 Deadline: deadline, 464 }) 465 } 466 467 // DecodeWorkerInfo decodes the given bytes into WorkerInfo. 468 func DecodeWorkerInfo(b []byte) (*WorkerInfo, error) { 469 var pbmsg pb.WorkerInfo 470 if err := proto.Unmarshal(b, &pbmsg); err != nil { 471 return nil, err 472 } 473 startTime := pbmsg.GetDeadline().AsTime() 474 if err := pbmsg.GetStartTime().CheckValid(); err != nil { 475 return nil, err 476 } 477 478 deadline := pbmsg.GetDeadline().AsTime() 479 if err := pbmsg.GetDeadline().CheckValid(); err != nil { 480 return nil, err 481 } 482 return &WorkerInfo{ 483 Host: pbmsg.GetHost(), 484 PID: int(pbmsg.GetPid()), 485 ServerID: pbmsg.GetServerId(), 486 ID: pbmsg.GetTaskId(), 487 Type: pbmsg.GetTaskType(), 488 Payload: pbmsg.GetTaskPayload(), 489 Queue: pbmsg.GetQueue(), 490 Started: startTime, 491 Deadline: deadline, 492 }, nil 493 } 494 495 // SchedulerEntry holds information about a periodic task registered with a scheduler. 496 type SchedulerEntry struct { 497 // Identifier of this entry. 498 ID string 499 500 // Spec describes the schedule of this entry. 501 Spec string 502 503 // Type is the task type of the periodic task. 504 Type string 505 506 // Payload is the payload of the periodic task. 507 Payload []byte 508 509 // Opts is the options for the periodic task. 510 Opts []string 511 512 // Next shows the next time the task will be enqueued. 513 Next time.Time 514 515 // Prev shows the last time the task was enqueued. 516 // Zero time if task was never enqueued. 517 Prev time.Time 518 } 519 520 // EncodeSchedulerEntry marshals the given entry and returns an encoded bytes. 521 func EncodeSchedulerEntry(entry *SchedulerEntry) ([]byte, error) { 522 if entry == nil { 523 return nil, fmt.Errorf("cannot encode nil scheduler entry") 524 } 525 next := timestamppb.New(entry.Next) 526 if err := next.CheckValid(); err != nil { 527 return nil, err 528 } 529 prev := timestamppb.New(entry.Prev) 530 if err := prev.CheckValid(); err != nil { 531 return nil, err 532 } 533 return proto.Marshal(&pb.SchedulerEntry{ 534 Id: entry.ID, 535 Spec: entry.Spec, 536 TaskType: entry.Type, 537 TaskPayload: entry.Payload, 538 EnqueueOptions: entry.Opts, 539 NextEnqueueTime: next, 540 PrevEnqueueTime: prev, 541 }) 542 } 543 544 // DecodeSchedulerEntry unmarshals the given bytes and returns a decoded SchedulerEntry. 545 func DecodeSchedulerEntry(b []byte) (*SchedulerEntry, error) { 546 var pbmsg pb.SchedulerEntry 547 if err := proto.Unmarshal(b, &pbmsg); err != nil { 548 return nil, err 549 } 550 next := pbmsg.GetNextEnqueueTime().AsTime() 551 if err := pbmsg.GetNextEnqueueTime().CheckValid(); err != nil { 552 return nil, err 553 } 554 prev := pbmsg.GetPrevEnqueueTime().AsTime() 555 if err := pbmsg.GetPrevEnqueueTime().CheckValid(); err != nil { 556 return nil, err 557 } 558 return &SchedulerEntry{ 559 ID: pbmsg.GetId(), 560 Spec: pbmsg.GetSpec(), 561 Type: pbmsg.GetTaskType(), 562 Payload: pbmsg.GetTaskPayload(), 563 Opts: pbmsg.GetEnqueueOptions(), 564 Next: next, 565 Prev: prev, 566 }, nil 567 } 568 569 // SchedulerEnqueueEvent holds information about an enqueue event by a scheduler. 570 type SchedulerEnqueueEvent struct { 571 // ID of the task that was enqueued. 572 TaskID string 573 574 // Time the task was enqueued. 575 EnqueuedAt time.Time 576 } 577 578 // EncodeSchedulerEnqueueEvent marshals the given event 579 // and returns an encoded bytes. 580 func EncodeSchedulerEnqueueEvent(event *SchedulerEnqueueEvent) ([]byte, error) { 581 if event == nil { 582 return nil, fmt.Errorf("cannot encode nil enqueue event") 583 } 584 enqueuedAt := timestamppb.New(event.EnqueuedAt) 585 if err := enqueuedAt.CheckValid(); err != nil { 586 return nil, err 587 } 588 return proto.Marshal(&pb.SchedulerEnqueueEvent{ 589 TaskId: event.TaskID, 590 EnqueueTime: enqueuedAt, 591 }) 592 } 593 594 // DecodeSchedulerEnqueueEvent unmarshals the given bytes 595 // and returns a decoded SchedulerEnqueueEvent. 596 func DecodeSchedulerEnqueueEvent(b []byte) (*SchedulerEnqueueEvent, error) { 597 var pbmsg pb.SchedulerEnqueueEvent 598 if err := proto.Unmarshal(b, &pbmsg); err != nil { 599 return nil, err 600 } 601 enqueuedAt := pbmsg.GetEnqueueTime().AsTime() 602 if err := pbmsg.GetEnqueueTime().CheckValid(); err != nil { 603 return nil, err 604 } 605 return &SchedulerEnqueueEvent{ 606 TaskID: pbmsg.GetTaskId(), 607 EnqueuedAt: enqueuedAt, 608 }, nil 609 } 610 611 // Cancelations is a collection that holds cancel functions for all active tasks. 612 // 613 // Cancelations are safe for concurrent use by multiple goroutines. 614 type Cancelations struct { 615 mu sync.Mutex 616 cancelFuncs map[string]context.CancelFunc 617 } 618 619 // NewCancelations returns a Cancelations instance. 620 func NewCancelations() *Cancelations { 621 return &Cancelations{ 622 cancelFuncs: make(map[string]context.CancelFunc), 623 } 624 } 625 626 // Add adds a new cancel func to the collection. 627 func (c *Cancelations) Add(id string, fn context.CancelFunc) { 628 c.mu.Lock() 629 defer c.mu.Unlock() 630 c.cancelFuncs[id] = fn 631 } 632 633 // Delete deletes a cancel func from the collection given an id. 634 func (c *Cancelations) Delete(id string) { 635 c.mu.Lock() 636 defer c.mu.Unlock() 637 delete(c.cancelFuncs, id) 638 } 639 640 // Get returns a cancel func given an id. 641 func (c *Cancelations) Get(id string) (fn context.CancelFunc, ok bool) { 642 c.mu.Lock() 643 defer c.mu.Unlock() 644 fn, ok = c.cancelFuncs[id] 645 return fn, ok 646 } 647 648 // Lease is a time bound lease for worker to process task. 649 // It provides a communication channel between lessor and lessee about lease expiration. 650 type Lease struct { 651 once sync.Once 652 ch chan struct{} 653 654 Clock timeutil.Clock 655 656 mu sync.Mutex 657 expireAt time.Time // guarded by mu 658 } 659 660 func NewLease(expirationTime time.Time) *Lease { 661 return &Lease{ 662 ch: make(chan struct{}), 663 expireAt: expirationTime, 664 Clock: timeutil.NewRealClock(), 665 } 666 } 667 668 // Reset changes the lease to expire at the given time. 669 // It returns true if the lease is still valid and reset operation was successful, false if the lease had been expired. 670 func (l *Lease) Reset(expirationTime time.Time) bool { 671 if !l.IsValid() { 672 return false 673 } 674 l.mu.Lock() 675 defer l.mu.Unlock() 676 l.expireAt = expirationTime 677 return true 678 } 679 680 // NotifyExpiration 681 // Sends a notification to lessee about expired lease. 682 // Returns true if notification was sent, returns false if the lease is still valid and notification was not sent. 683 func (l *Lease) NotifyExpiration() bool { 684 if l.IsValid() { 685 return false 686 } 687 l.once.Do(l.closeCh) 688 return true 689 } 690 691 func (l *Lease) closeCh() { 692 close(l.ch) 693 } 694 695 // Done returns a communication channel from which the lessee can read to get notified 696 // when lessor notifies about lease expiration. 697 func (l *Lease) Done() <-chan struct{} { 698 return l.ch 699 } 700 701 // Deadline returns the expiration time of the lease. 702 func (l *Lease) Deadline() time.Time { 703 l.mu.Lock() 704 defer l.mu.Unlock() 705 return l.expireAt 706 } 707 708 // IsValid returns true if the lease's expiration time is in the future or equals to the current time, 709 // returns false otherwise. 710 func (l *Lease) IsValid() bool { 711 now := l.Clock.Now() 712 l.mu.Lock() 713 defer l.mu.Unlock() 714 return l.expireAt.After(now) || l.expireAt.Equal(now) 715 } 716 717 // Broker is a message broker that supports operations to manage task queues. 718 // 719 // See rdb.RDB as a reference implementation. 720 //nolint: revive // interface too long issue 721 type Broker interface { 722 Ping() error 723 Close() error 724 Enqueue(ctx context.Context, msg *TaskMessage) error 725 EnqueueUnique(ctx context.Context, msg *TaskMessage, ttl time.Duration) error 726 Dequeue(qnames ...string) (*TaskMessage, time.Time, error) 727 Done(ctx context.Context, msg *TaskMessage) error 728 MarkAsComplete(ctx context.Context, msg *TaskMessage) error 729 Requeue(ctx context.Context, msg *TaskMessage) error 730 Schedule(ctx context.Context, msg *TaskMessage, processAt time.Time) error 731 ScheduleUnique(ctx context.Context, msg *TaskMessage, processAt time.Time, ttl time.Duration) error 732 Retry(ctx context.Context, msg *TaskMessage, processAt time.Time, errMsg string, isFailure bool) error 733 Archive(ctx context.Context, msg *TaskMessage, errMsg string) error 734 ForwardIfReady(qnames ...string) error 735 736 // Group aggregation related methods 737 AddToGroup(ctx context.Context, msg *TaskMessage, gname string) error 738 AddToGroupUnique(ctx context.Context, msg *TaskMessage, uniqueKey, groupKey string, ttl time.Duration) error 739 ListGroups(qname string) ([]string, error) 740 AggregationCheck(qname, gname string, t time.Time, gracePeriod, maxDelay time.Duration, maxSize int) (aggregationSetID string, err error) 741 ReadAggregationSet(qname, gname, aggregationSetID string) ([]*TaskMessage, time.Time, error) 742 DeleteAggregationSet(ctx context.Context, qname, gname, aggregationSetID string) error 743 ReclaimStaleAggregationSets(qname string) error 744 745 // Task retention related method 746 DeleteExpiredCompletedTasks(qname string) error 747 748 // Lease related methods 749 ListLeaseExpired(cutoff time.Time, qnames ...string) ([]*TaskMessage, error) 750 ExtendLease(qname string, ids ...string) (time.Time, error) 751 752 // State snapshot related methods 753 WriteServerState(info *ServerInfo, workers []*WorkerInfo, ttl time.Duration) error 754 ClearServerState(host string, pid int, serverID string) error 755 756 // Cancelation related methods 757 CancelationPubSub() (*redis.PubSub, error) // TODO: Need to decouple from redis to support other brokers 758 PublishCancelation(id string) error 759 760 WriteResult(qname, id string, data []byte) (n int, err error) 761 }