go.temporal.io/server@v1.23.0/common/persistence/sql/execution_tasks.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package sql 26 27 import ( 28 "context" 29 "database/sql" 30 "encoding/json" 31 "errors" 32 "fmt" 33 "math" 34 "time" 35 36 "go.temporal.io/api/serviceerror" 37 38 p "go.temporal.io/server/common/persistence" 39 "go.temporal.io/server/common/persistence/serialization" 40 "go.temporal.io/server/common/persistence/sql/sqlplugin" 41 "go.temporal.io/server/service/history/tasks" 42 ) 43 44 func (m *sqlExecutionStore) RegisterHistoryTaskReader( 45 _ context.Context, 46 _ *p.RegisterHistoryTaskReaderRequest, 47 ) error { 48 // no-op 49 return nil 50 } 51 52 func (m *sqlExecutionStore) UnregisterHistoryTaskReader( 53 _ context.Context, 54 _ *p.UnregisterHistoryTaskReaderRequest, 55 ) { 56 // no-op 57 } 58 59 func (m *sqlExecutionStore) UpdateHistoryTaskReaderProgress( 60 _ context.Context, 61 _ *p.UpdateHistoryTaskReaderProgressRequest, 62 ) { 63 // no-op 64 } 65 66 func (m *sqlExecutionStore) AddHistoryTasks( 67 ctx context.Context, 68 request *p.InternalAddHistoryTasksRequest, 69 ) error { 70 return m.txExecuteShardLocked(ctx, 71 "AddHistoryTasks", 72 request.ShardID, 73 request.RangeID, 74 func(tx sqlplugin.Tx) error { 75 return applyTasks(ctx, 76 tx, 77 request.ShardID, 78 request.Tasks, 79 ) 80 }) 81 } 82 83 func (m *sqlExecutionStore) GetHistoryTasks( 84 ctx context.Context, 85 request *p.GetHistoryTasksRequest, 86 ) (*p.InternalGetHistoryTasksResponse, error) { 87 switch request.TaskCategory.Type() { 88 case tasks.CategoryTypeImmediate: 89 return m.getHistoryImmediateTasks(ctx, request) 90 case tasks.CategoryTypeScheduled: 91 return m.getHistoryScheduledTasks(ctx, request) 92 default: 93 return nil, serviceerror.NewInternal(fmt.Sprintf("Unknown task category type: %v", request.TaskCategory)) 94 } 95 } 96 97 func (m *sqlExecutionStore) CompleteHistoryTask( 98 ctx context.Context, 99 request *p.CompleteHistoryTaskRequest, 100 ) error { 101 switch request.TaskCategory.Type() { 102 case tasks.CategoryTypeImmediate: 103 return m.completeHistoryImmediateTask(ctx, request) 104 case tasks.CategoryTypeScheduled: 105 return m.completeHistoryScheduledTask(ctx, request) 106 default: 107 return serviceerror.NewInternal(fmt.Sprintf("Unknown task category type: %v", request.TaskCategory)) 108 } 109 } 110 111 func (m *sqlExecutionStore) RangeCompleteHistoryTasks( 112 ctx context.Context, 113 request *p.RangeCompleteHistoryTasksRequest, 114 ) error { 115 switch request.TaskCategory.Type() { 116 case tasks.CategoryTypeImmediate: 117 return m.rangeCompleteHistoryImmediateTasks(ctx, request) 118 case tasks.CategoryTypeScheduled: 119 return m.rangeCompleteHistoryScheduledTasks(ctx, request) 120 default: 121 return serviceerror.NewInternal(fmt.Sprintf("Unknown task category type: %v", request.TaskCategory)) 122 } 123 } 124 125 func (m *sqlExecutionStore) getHistoryImmediateTasks( 126 ctx context.Context, 127 request *p.GetHistoryTasksRequest, 128 ) (*p.InternalGetHistoryTasksResponse, error) { 129 // This is for backward compatiblity. 130 // These task categories exist before the general history_immediate_tasks table is created, 131 // so they have their own tables. 132 categoryID := request.TaskCategory.ID() 133 switch categoryID { 134 case tasks.CategoryIDTransfer: 135 return m.getTransferTasks(ctx, request) 136 case tasks.CategoryIDVisibility: 137 return m.getVisibilityTasks(ctx, request) 138 case tasks.CategoryIDReplication: 139 return m.getReplicationTasks(ctx, request) 140 } 141 142 inclusiveMinTaskID, exclusiveMaxTaskID, err := getImmediateTaskReadRange(request) 143 if err != nil { 144 return nil, err 145 } 146 147 rows, err := m.Db.RangeSelectFromHistoryImmediateTasks(ctx, sqlplugin.HistoryImmediateTasksRangeFilter{ 148 ShardID: request.ShardID, 149 CategoryID: int32(categoryID), 150 InclusiveMinTaskID: inclusiveMinTaskID, 151 ExclusiveMaxTaskID: exclusiveMaxTaskID, 152 PageSize: request.BatchSize, 153 }) 154 if err != nil { 155 if err != sql.ErrNoRows { 156 return nil, serviceerror.NewUnavailable( 157 fmt.Sprintf("GetHistoryTasks operation failed. Select failed. CategoryID: %v. Error: %v", categoryID, err), 158 ) 159 } 160 } 161 resp := &p.InternalGetHistoryTasksResponse{ 162 Tasks: make([]p.InternalHistoryTask, len(rows)), 163 } 164 if len(rows) == 0 { 165 return resp, nil 166 } 167 168 for i, row := range rows { 169 resp.Tasks[i] = p.InternalHistoryTask{ 170 Key: tasks.NewImmediateKey(row.TaskID), 171 Blob: p.NewDataBlob(row.Data, row.DataEncoding), 172 } 173 } 174 if len(rows) == request.BatchSize { 175 resp.NextPageToken = getImmediateTaskNextPageToken( 176 rows[len(rows)-1].TaskID, 177 exclusiveMaxTaskID, 178 ) 179 } 180 181 return resp, nil 182 } 183 184 func (m *sqlExecutionStore) completeHistoryImmediateTask( 185 ctx context.Context, 186 request *p.CompleteHistoryTaskRequest, 187 ) error { 188 // This is for backward compatiblity. 189 // These task categories exist before the general history_immediate_tasks table is created, 190 // so they have their own tables. 191 categoryID := request.TaskCategory.ID() 192 switch categoryID { 193 case tasks.CategoryIDTransfer: 194 return m.completeTransferTask(ctx, request) 195 case tasks.CategoryIDVisibility: 196 return m.completeVisibilityTask(ctx, request) 197 case tasks.CategoryIDReplication: 198 return m.completeReplicationTask(ctx, request) 199 } 200 201 if _, err := m.Db.DeleteFromHistoryImmediateTasks(ctx, sqlplugin.HistoryImmediateTasksFilter{ 202 ShardID: request.ShardID, 203 CategoryID: int32(categoryID), 204 TaskID: request.TaskKey.TaskID, 205 }); err != nil { 206 return serviceerror.NewUnavailable( 207 fmt.Sprintf("CompleteHistoryTask operation failed. CategoryID: %v. Error: %v", categoryID, err), 208 ) 209 } 210 return nil 211 } 212 213 func (m *sqlExecutionStore) rangeCompleteHistoryImmediateTasks( 214 ctx context.Context, 215 request *p.RangeCompleteHistoryTasksRequest, 216 ) error { 217 // This is for backward compatiblity. 218 // These task categories exist before the general history_immediate_tasks table is created, 219 // so they have their own tables. 220 categoryID := request.TaskCategory.ID() 221 switch categoryID { 222 case tasks.CategoryIDTransfer: 223 return m.rangeCompleteTransferTasks(ctx, request) 224 case tasks.CategoryIDVisibility: 225 return m.rangeCompleteVisibilityTasks(ctx, request) 226 case tasks.CategoryIDReplication: 227 return m.rangeCompleteReplicationTasks(ctx, request) 228 } 229 230 if _, err := m.Db.RangeDeleteFromHistoryImmediateTasks(ctx, sqlplugin.HistoryImmediateTasksRangeFilter{ 231 ShardID: request.ShardID, 232 CategoryID: int32(categoryID), 233 InclusiveMinTaskID: request.InclusiveMinTaskKey.TaskID, 234 ExclusiveMaxTaskID: request.ExclusiveMaxTaskKey.TaskID, 235 }); err != nil { 236 return serviceerror.NewUnavailable( 237 fmt.Sprintf("RangeCompleteTransferTask operation failed. CategoryID: %v. Error: %v", categoryID, err), 238 ) 239 } 240 return nil 241 } 242 243 func (m *sqlExecutionStore) getHistoryScheduledTasks( 244 ctx context.Context, 245 request *p.GetHistoryTasksRequest, 246 ) (*p.InternalGetHistoryTasksResponse, error) { 247 // This is for backward compatiblity. 248 // These task categories exist before the general history_scheduled_tasks table is created, 249 // so they have their own tables. 250 categoryID := request.TaskCategory.ID() 251 if categoryID == tasks.CategoryIDTimer { 252 return m.getTimerTasks(ctx, request) 253 } 254 255 pageToken := &scheduledTaskPageToken{TaskID: math.MinInt64, Timestamp: request.InclusiveMinTaskKey.FireTime} 256 if len(request.NextPageToken) > 0 { 257 if err := pageToken.deserialize(request.NextPageToken); err != nil { 258 return nil, serviceerror.NewInternal( 259 fmt.Sprintf("categoryID: %v. error deserializing scheduledTaskPageToken: %v", categoryID, err), 260 ) 261 } 262 } 263 264 rows, err := m.Db.RangeSelectFromHistoryScheduledTasks(ctx, sqlplugin.HistoryScheduledTasksRangeFilter{ 265 ShardID: request.ShardID, 266 CategoryID: int32(categoryID), 267 InclusiveMinVisibilityTimestamp: pageToken.Timestamp, 268 InclusiveMinTaskID: pageToken.TaskID, 269 ExclusiveMaxVisibilityTimestamp: request.ExclusiveMaxTaskKey.FireTime, 270 PageSize: request.BatchSize, 271 }) 272 273 if err != nil && err != sql.ErrNoRows { 274 return nil, serviceerror.NewUnavailable( 275 fmt.Sprintf("GetHistoryTasks operation failed. Select failed. CategoryID: %v. Error: %v", categoryID, err), 276 ) 277 } 278 279 resp := &p.InternalGetHistoryTasksResponse{Tasks: make([]p.InternalHistoryTask, 0, len(rows))} 280 for _, row := range rows { 281 resp.Tasks = append(resp.Tasks, p.InternalHistoryTask{ 282 Key: tasks.NewKey(row.VisibilityTimestamp, row.TaskID), 283 Blob: p.NewDataBlob(row.Data, row.DataEncoding), 284 }) 285 } 286 287 if len(resp.Tasks) == request.BatchSize { 288 pageToken = &scheduledTaskPageToken{ 289 TaskID: rows[request.BatchSize-1].TaskID + 1, 290 Timestamp: rows[request.BatchSize-1].VisibilityTimestamp, 291 } 292 nextToken, err := pageToken.serialize() 293 if err != nil { 294 return nil, serviceerror.NewInternal(fmt.Sprintf("GetHistoryTasks: error serializing page token: %v", err)) 295 } 296 resp.NextPageToken = nextToken 297 } 298 299 return resp, nil 300 } 301 302 func (m *sqlExecutionStore) completeHistoryScheduledTask( 303 ctx context.Context, 304 request *p.CompleteHistoryTaskRequest, 305 ) error { 306 // This is for backward compatiblity. 307 // These task categories exist before the general history_scheduled_tasks table is created, 308 // so they have their own tables. 309 categoryID := request.TaskCategory.ID() 310 if categoryID == tasks.CategoryIDTimer { 311 return m.completeTimerTask(ctx, request) 312 } 313 314 if _, err := m.Db.DeleteFromHistoryScheduledTasks(ctx, sqlplugin.HistoryScheduledTasksFilter{ 315 ShardID: request.ShardID, 316 CategoryID: int32(categoryID), 317 VisibilityTimestamp: request.TaskKey.FireTime, 318 TaskID: request.TaskKey.TaskID, 319 }); err != nil { 320 return serviceerror.NewUnavailable(fmt.Sprintf("CompleteHistoryTask operation failed. CategoryID: %v. Error: %v", categoryID, err)) 321 } 322 return nil 323 } 324 325 func (m *sqlExecutionStore) rangeCompleteHistoryScheduledTasks( 326 ctx context.Context, 327 request *p.RangeCompleteHistoryTasksRequest, 328 ) error { 329 // This is for backward compatiblity. 330 // These task categories exist before the general history_scheduled_tasks table is created, 331 // so they have their own tables. 332 categoryID := request.TaskCategory.ID() 333 if categoryID == tasks.CategoryIDTimer { 334 return m.rangeCompleteTimerTasks(ctx, request) 335 } 336 337 start := request.InclusiveMinTaskKey.FireTime 338 end := request.ExclusiveMaxTaskKey.FireTime 339 if _, err := m.Db.RangeDeleteFromHistoryScheduledTasks(ctx, sqlplugin.HistoryScheduledTasksRangeFilter{ 340 ShardID: request.ShardID, 341 CategoryID: int32(categoryID), 342 InclusiveMinVisibilityTimestamp: start, 343 ExclusiveMaxVisibilityTimestamp: end, 344 }); err != nil { 345 return serviceerror.NewUnavailable(fmt.Sprintf("RangeCompleteHistoryTask operation failed. CategoryID: %v. Error: %v", categoryID, err)) 346 } 347 return nil 348 } 349 350 func (m *sqlExecutionStore) getTransferTasks( 351 ctx context.Context, 352 request *p.GetHistoryTasksRequest, 353 ) (*p.InternalGetHistoryTasksResponse, error) { 354 inclusiveMinTaskID, exclusiveMaxTaskID, err := getImmediateTaskReadRange(request) 355 if err != nil { 356 return nil, err 357 } 358 359 rows, err := m.Db.RangeSelectFromTransferTasks(ctx, sqlplugin.TransferTasksRangeFilter{ 360 ShardID: request.ShardID, 361 InclusiveMinTaskID: inclusiveMinTaskID, 362 ExclusiveMaxTaskID: exclusiveMaxTaskID, 363 PageSize: request.BatchSize, 364 }) 365 if err != nil { 366 if err != sql.ErrNoRows { 367 return nil, serviceerror.NewUnavailable(fmt.Sprintf("GetTransferTasks operation failed. Select failed. Error: %v", err)) 368 } 369 } 370 resp := &p.InternalGetHistoryTasksResponse{ 371 Tasks: make([]p.InternalHistoryTask, len(rows)), 372 } 373 if len(rows) == 0 { 374 return resp, nil 375 } 376 377 for i, row := range rows { 378 resp.Tasks[i] = p.InternalHistoryTask{ 379 Key: tasks.NewImmediateKey(row.TaskID), 380 Blob: p.NewDataBlob(row.Data, row.DataEncoding), 381 } 382 } 383 if len(rows) == request.BatchSize { 384 resp.NextPageToken = getImmediateTaskNextPageToken( 385 rows[len(rows)-1].TaskID, 386 exclusiveMaxTaskID, 387 ) 388 } 389 390 return resp, nil 391 } 392 393 func (m *sqlExecutionStore) completeTransferTask( 394 ctx context.Context, 395 request *p.CompleteHistoryTaskRequest, 396 ) error { 397 if _, err := m.Db.DeleteFromTransferTasks(ctx, sqlplugin.TransferTasksFilter{ 398 ShardID: request.ShardID, 399 TaskID: request.TaskKey.TaskID, 400 }); err != nil { 401 return serviceerror.NewUnavailable(fmt.Sprintf("CompleteTransferTask operation failed. Error: %v", err)) 402 } 403 return nil 404 } 405 406 func (m *sqlExecutionStore) rangeCompleteTransferTasks( 407 ctx context.Context, 408 request *p.RangeCompleteHistoryTasksRequest, 409 ) error { 410 if _, err := m.Db.RangeDeleteFromTransferTasks(ctx, sqlplugin.TransferTasksRangeFilter{ 411 ShardID: request.ShardID, 412 InclusiveMinTaskID: request.InclusiveMinTaskKey.TaskID, 413 ExclusiveMaxTaskID: request.ExclusiveMaxTaskKey.TaskID, 414 }); err != nil { 415 return serviceerror.NewUnavailable(fmt.Sprintf("RangeCompleteTransferTask operation failed. Error: %v", err)) 416 } 417 return nil 418 } 419 420 func (m *sqlExecutionStore) getTimerTasks( 421 ctx context.Context, 422 request *p.GetHistoryTasksRequest, 423 ) (*p.InternalGetHistoryTasksResponse, error) { 424 pageToken := &scheduledTaskPageToken{TaskID: math.MinInt64, Timestamp: request.InclusiveMinTaskKey.FireTime} 425 if len(request.NextPageToken) > 0 { 426 if err := pageToken.deserialize(request.NextPageToken); err != nil { 427 return nil, serviceerror.NewInternal(fmt.Sprintf("error deserializing timerTaskPageToken: %v", err)) 428 } 429 } 430 431 rows, err := m.Db.RangeSelectFromTimerTasks(ctx, sqlplugin.TimerTasksRangeFilter{ 432 ShardID: request.ShardID, 433 InclusiveMinVisibilityTimestamp: pageToken.Timestamp, 434 InclusiveMinTaskID: pageToken.TaskID, 435 ExclusiveMaxVisibilityTimestamp: request.ExclusiveMaxTaskKey.FireTime, 436 PageSize: request.BatchSize, 437 }) 438 439 if err != nil && err != sql.ErrNoRows { 440 return nil, serviceerror.NewUnavailable(fmt.Sprintf("GetTimerTasks operation failed. Select failed. Error: %v", err)) 441 } 442 443 resp := &p.InternalGetHistoryTasksResponse{Tasks: make([]p.InternalHistoryTask, 0, len(rows))} 444 for _, row := range rows { 445 resp.Tasks = append(resp.Tasks, p.InternalHistoryTask{ 446 Key: tasks.NewKey(row.VisibilityTimestamp, row.TaskID), 447 Blob: p.NewDataBlob(row.Data, row.DataEncoding), 448 }) 449 } 450 451 if len(resp.Tasks) == request.BatchSize { 452 pageToken = &scheduledTaskPageToken{ 453 TaskID: rows[request.BatchSize-1].TaskID + 1, 454 Timestamp: rows[request.BatchSize-1].VisibilityTimestamp, 455 } 456 nextToken, err := pageToken.serialize() 457 if err != nil { 458 return nil, serviceerror.NewInternal(fmt.Sprintf("GetTimerTasks: error serializing page token: %v", err)) 459 } 460 resp.NextPageToken = nextToken 461 } 462 463 return resp, nil 464 } 465 466 func (m *sqlExecutionStore) completeTimerTask( 467 ctx context.Context, 468 request *p.CompleteHistoryTaskRequest, 469 ) error { 470 if _, err := m.Db.DeleteFromTimerTasks(ctx, sqlplugin.TimerTasksFilter{ 471 ShardID: request.ShardID, 472 VisibilityTimestamp: request.TaskKey.FireTime, 473 TaskID: request.TaskKey.TaskID, 474 }); err != nil { 475 return serviceerror.NewUnavailable(fmt.Sprintf("CompleteTimerTask operation failed. Error: %v", err)) 476 } 477 return nil 478 } 479 480 func (m *sqlExecutionStore) rangeCompleteTimerTasks( 481 ctx context.Context, 482 request *p.RangeCompleteHistoryTasksRequest, 483 ) error { 484 start := request.InclusiveMinTaskKey.FireTime 485 end := request.ExclusiveMaxTaskKey.FireTime 486 if _, err := m.Db.RangeDeleteFromTimerTasks(ctx, sqlplugin.TimerTasksRangeFilter{ 487 ShardID: request.ShardID, 488 InclusiveMinVisibilityTimestamp: start, 489 ExclusiveMaxVisibilityTimestamp: end, 490 }); err != nil { 491 return serviceerror.NewUnavailable(fmt.Sprintf("RangeCompleteTimerTask operation failed. Error: %v", err)) 492 } 493 return nil 494 } 495 496 func (m *sqlExecutionStore) getReplicationTasks( 497 ctx context.Context, 498 request *p.GetHistoryTasksRequest, 499 ) (*p.InternalGetHistoryTasksResponse, error) { 500 inclusiveMinTaskID, exclusiveMaxTaskID, err := getImmediateTaskReadRange(request) 501 if err != nil { 502 return nil, err 503 } 504 505 rows, err := m.Db.RangeSelectFromReplicationTasks(ctx, sqlplugin.ReplicationTasksRangeFilter{ 506 ShardID: request.ShardID, 507 InclusiveMinTaskID: inclusiveMinTaskID, 508 ExclusiveMaxTaskID: exclusiveMaxTaskID, 509 PageSize: request.BatchSize, 510 }) 511 512 switch err { 513 case nil: 514 return m.populateGetReplicationTasksResponse(rows, request.ExclusiveMaxTaskKey.TaskID, request.BatchSize) 515 case sql.ErrNoRows: 516 return &p.InternalGetHistoryTasksResponse{}, nil 517 default: 518 return nil, serviceerror.NewUnavailable(fmt.Sprintf("GetReplicationTasks operation failed. Select failed: %v", err)) 519 } 520 } 521 522 func getImmediateTaskReadRange( 523 request *p.GetHistoryTasksRequest, 524 ) (inclusiveMinTaskID int64, exclusiveMaxTaskID int64, err error) { 525 inclusiveMinTaskID = request.InclusiveMinTaskKey.TaskID 526 if len(request.NextPageToken) > 0 { 527 inclusiveMinTaskID, err = deserializePageToken(request.NextPageToken) 528 if err != nil { 529 return 0, 0, err 530 } 531 } 532 533 return inclusiveMinTaskID, request.ExclusiveMaxTaskKey.TaskID, nil 534 } 535 536 func getImmediateTaskNextPageToken( 537 lastTaskID int64, 538 exclusiveMaxTaskID int64, 539 ) []byte { 540 nextTaskID := lastTaskID + 1 541 if nextTaskID < exclusiveMaxTaskID { 542 return serializePageToken(nextTaskID) 543 } 544 return nil 545 } 546 547 func (m *sqlExecutionStore) populateGetReplicationTasksResponse( 548 rows []sqlplugin.ReplicationTasksRow, 549 exclusiveMaxTaskID int64, 550 batchSize int, 551 ) (*p.InternalGetHistoryTasksResponse, error) { 552 if len(rows) == 0 { 553 return &p.InternalGetHistoryTasksResponse{}, nil 554 } 555 556 var replicationTasks = make([]p.InternalHistoryTask, len(rows)) 557 for i, row := range rows { 558 replicationTasks[i] = p.InternalHistoryTask{ 559 Key: tasks.NewImmediateKey(row.TaskID), 560 Blob: p.NewDataBlob(row.Data, row.DataEncoding), 561 } 562 } 563 var nextPageToken []byte 564 if len(rows) == batchSize { 565 nextPageToken = getImmediateTaskNextPageToken( 566 rows[len(rows)-1].TaskID, 567 exclusiveMaxTaskID, 568 ) 569 } 570 return &p.InternalGetHistoryTasksResponse{ 571 Tasks: replicationTasks, 572 NextPageToken: nextPageToken, 573 }, nil 574 } 575 576 func (m *sqlExecutionStore) populateGetReplicationDLQTasksResponse( 577 rows []sqlplugin.ReplicationDLQTasksRow, 578 exclusiveMaxTaskID int64, 579 batchSize int, 580 ) (*p.InternalGetHistoryTasksResponse, error) { 581 if len(rows) == 0 { 582 return &p.InternalGetHistoryTasksResponse{}, nil 583 } 584 585 var dlqTasks = make([]p.InternalHistoryTask, len(rows)) 586 for i, row := range rows { 587 dlqTasks[i] = p.InternalHistoryTask{ 588 Key: tasks.NewImmediateKey(row.TaskID), 589 Blob: p.NewDataBlob(row.Data, row.DataEncoding), 590 } 591 } 592 var nextPageToken []byte 593 if len(rows) == batchSize { 594 nextPageToken = getImmediateTaskNextPageToken( 595 rows[len(rows)-1].TaskID, 596 exclusiveMaxTaskID, 597 ) 598 } 599 return &p.InternalGetHistoryTasksResponse{ 600 Tasks: dlqTasks, 601 NextPageToken: nextPageToken, 602 }, nil 603 } 604 605 func (m *sqlExecutionStore) completeReplicationTask( 606 ctx context.Context, 607 request *p.CompleteHistoryTaskRequest, 608 ) error { 609 if _, err := m.Db.DeleteFromReplicationTasks(ctx, sqlplugin.ReplicationTasksFilter{ 610 ShardID: request.ShardID, 611 TaskID: request.TaskKey.TaskID, 612 }); err != nil { 613 return serviceerror.NewUnavailable(fmt.Sprintf("CompleteReplicationTask operation failed. Error: %v", err)) 614 } 615 return nil 616 } 617 618 func (m *sqlExecutionStore) rangeCompleteReplicationTasks( 619 ctx context.Context, 620 request *p.RangeCompleteHistoryTasksRequest, 621 ) error { 622 if _, err := m.Db.RangeDeleteFromReplicationTasks(ctx, sqlplugin.ReplicationTasksRangeFilter{ 623 ShardID: request.ShardID, 624 InclusiveMinTaskID: request.InclusiveMinTaskKey.TaskID, 625 ExclusiveMaxTaskID: request.ExclusiveMaxTaskKey.TaskID, 626 }); err != nil { 627 return serviceerror.NewUnavailable(fmt.Sprintf("RangeCompleteReplicationTask operation failed. Error: %v", err)) 628 } 629 return nil 630 } 631 632 func (m *sqlExecutionStore) PutReplicationTaskToDLQ( 633 ctx context.Context, 634 request *p.PutReplicationTaskToDLQRequest, 635 ) error { 636 replicationTask := request.TaskInfo 637 blob, err := serialization.ReplicationTaskInfoToBlob(replicationTask) 638 639 if err != nil { 640 return err 641 } 642 643 _, err = m.Db.InsertIntoReplicationDLQTasks(ctx, []sqlplugin.ReplicationDLQTasksRow{{ 644 SourceClusterName: request.SourceClusterName, 645 ShardID: request.ShardID, 646 TaskID: replicationTask.GetTaskId(), 647 Data: blob.Data, 648 DataEncoding: blob.EncodingType.String(), 649 }}) 650 651 // Tasks are immutable. So it's fine if we already persisted it before. 652 // This can happen when tasks are retried (ack and cleanup can have lag on source side). 653 if err != nil && !m.Db.IsDupEntryError(err) { 654 return serviceerror.NewUnavailable(fmt.Sprintf("Failed to create replication tasks. Error: %v", err)) 655 } 656 657 return nil 658 } 659 660 func (m *sqlExecutionStore) GetReplicationTasksFromDLQ( 661 ctx context.Context, 662 request *p.GetReplicationTasksFromDLQRequest, 663 ) (*p.InternalGetHistoryTasksResponse, error) { 664 inclusiveMinTaskID, exclusiveMaxTaskID, err := getImmediateTaskReadRange(&request.GetHistoryTasksRequest) 665 if err != nil { 666 return nil, err 667 } 668 669 rows, err := m.Db.RangeSelectFromReplicationDLQTasks(ctx, sqlplugin.ReplicationDLQTasksRangeFilter{ 670 ShardID: request.ShardID, 671 InclusiveMinTaskID: inclusiveMinTaskID, 672 ExclusiveMaxTaskID: exclusiveMaxTaskID, 673 PageSize: request.BatchSize, 674 SourceClusterName: request.SourceClusterName, 675 }) 676 677 switch err { 678 case nil: 679 return m.populateGetReplicationDLQTasksResponse(rows, request.ExclusiveMaxTaskKey.TaskID, request.BatchSize) 680 case sql.ErrNoRows: 681 return &p.InternalGetHistoryTasksResponse{}, nil 682 default: 683 return nil, serviceerror.NewUnavailable(fmt.Sprintf("GetReplicationTasks operation failed. Select failed: %v", err)) 684 } 685 } 686 687 func (m *sqlExecutionStore) DeleteReplicationTaskFromDLQ( 688 ctx context.Context, 689 request *p.DeleteReplicationTaskFromDLQRequest, 690 ) error { 691 if _, err := m.Db.DeleteFromReplicationDLQTasks(ctx, sqlplugin.ReplicationDLQTasksFilter{ 692 ShardID: request.ShardID, 693 TaskID: request.TaskKey.TaskID, 694 SourceClusterName: request.SourceClusterName, 695 }); err != nil { 696 return err 697 } 698 return nil 699 } 700 701 func (m *sqlExecutionStore) RangeDeleteReplicationTaskFromDLQ( 702 ctx context.Context, 703 request *p.RangeDeleteReplicationTaskFromDLQRequest, 704 ) error { 705 if _, err := m.Db.RangeDeleteFromReplicationDLQTasks(ctx, sqlplugin.ReplicationDLQTasksRangeFilter{ 706 ShardID: request.ShardID, 707 SourceClusterName: request.SourceClusterName, 708 InclusiveMinTaskID: request.InclusiveMinTaskKey.TaskID, 709 ExclusiveMaxTaskID: request.ExclusiveMaxTaskKey.TaskID, 710 }); err != nil { 711 return err 712 } 713 return nil 714 } 715 716 func (m *sqlExecutionStore) IsReplicationDLQEmpty( 717 ctx context.Context, 718 request *p.GetReplicationTasksFromDLQRequest, 719 ) (bool, error) { 720 res, err := m.Db.RangeSelectFromReplicationDLQTasks(ctx, sqlplugin.ReplicationDLQTasksRangeFilter{ 721 ShardID: request.ShardID, 722 SourceClusterName: request.SourceClusterName, 723 InclusiveMinTaskID: request.InclusiveMinTaskKey.TaskID, 724 ExclusiveMaxTaskID: math.MaxInt64, 725 PageSize: 1, 726 }) 727 if err != nil { 728 if errors.Is(err, sql.ErrNoRows) { 729 // The queue is empty 730 return true, nil 731 } 732 return false, err 733 } 734 return len(res) == 0, nil 735 } 736 737 func (m *sqlExecutionStore) getVisibilityTasks( 738 ctx context.Context, 739 request *p.GetHistoryTasksRequest, 740 ) (*p.InternalGetHistoryTasksResponse, error) { 741 inclusiveMinTaskID, exclusiveMaxTaskID, err := getImmediateTaskReadRange(request) 742 if err != nil { 743 return nil, err 744 } 745 746 rows, err := m.Db.RangeSelectFromVisibilityTasks(ctx, sqlplugin.VisibilityTasksRangeFilter{ 747 ShardID: request.ShardID, 748 InclusiveMinTaskID: inclusiveMinTaskID, 749 ExclusiveMaxTaskID: exclusiveMaxTaskID, 750 PageSize: request.BatchSize, 751 }) 752 if err != nil { 753 if err != sql.ErrNoRows { 754 return nil, serviceerror.NewUnavailable(fmt.Sprintf("GetVisibilityTasks operation failed. Select failed. Error: %v", err)) 755 } 756 } 757 resp := &p.InternalGetHistoryTasksResponse{ 758 Tasks: make([]p.InternalHistoryTask, len(rows)), 759 } 760 if len(rows) == 0 { 761 return resp, nil 762 } 763 764 for i, row := range rows { 765 resp.Tasks[i] = p.InternalHistoryTask{ 766 Key: tasks.NewImmediateKey(row.TaskID), 767 Blob: p.NewDataBlob(row.Data, row.DataEncoding), 768 } 769 } 770 if len(rows) == request.BatchSize { 771 resp.NextPageToken = getImmediateTaskNextPageToken( 772 rows[len(rows)-1].TaskID, 773 exclusiveMaxTaskID, 774 ) 775 } 776 777 return resp, nil 778 } 779 780 func (m *sqlExecutionStore) completeVisibilityTask( 781 ctx context.Context, 782 request *p.CompleteHistoryTaskRequest, 783 ) error { 784 if _, err := m.Db.DeleteFromVisibilityTasks(ctx, sqlplugin.VisibilityTasksFilter{ 785 ShardID: request.ShardID, 786 TaskID: request.TaskKey.TaskID, 787 }); err != nil { 788 return serviceerror.NewUnavailable(fmt.Sprintf("CompleteVisibilityTask operation failed. Error: %v", err)) 789 } 790 return nil 791 } 792 793 func (m *sqlExecutionStore) rangeCompleteVisibilityTasks( 794 ctx context.Context, 795 request *p.RangeCompleteHistoryTasksRequest, 796 ) error { 797 if _, err := m.Db.RangeDeleteFromVisibilityTasks(ctx, sqlplugin.VisibilityTasksRangeFilter{ 798 ShardID: request.ShardID, 799 InclusiveMinTaskID: request.InclusiveMinTaskKey.TaskID, 800 ExclusiveMaxTaskID: request.ExclusiveMaxTaskKey.TaskID, 801 }); err != nil { 802 return serviceerror.NewUnavailable(fmt.Sprintf("RangeCompleteVisibilityTask operation failed. Error: %v", err)) 803 } 804 return nil 805 } 806 807 type scheduledTaskPageToken struct { 808 TaskID int64 809 Timestamp time.Time 810 } 811 812 func (t *scheduledTaskPageToken) serialize() ([]byte, error) { 813 return json.Marshal(t) 814 } 815 816 func (t *scheduledTaskPageToken) deserialize(payload []byte) error { 817 return json.Unmarshal(payload, t) 818 }