go.temporal.io/server@v1.23.0/common/persistence/visibility/store/standard/cassandra/visibility_store.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 cassandra 26 27 import ( 28 "context" 29 "time" 30 31 "github.com/gocql/gocql" 32 enumspb "go.temporal.io/api/enums/v1" 33 34 "go.temporal.io/server/common/config" 35 "go.temporal.io/server/common/log" 36 "go.temporal.io/server/common/log/tag" 37 "go.temporal.io/server/common/metrics" 38 "go.temporal.io/server/common/persistence" 39 commongocql "go.temporal.io/server/common/persistence/nosql/nosqlplugin/cassandra/gocql" 40 "go.temporal.io/server/common/persistence/visibility/manager" 41 "go.temporal.io/server/common/persistence/visibility/store" 42 "go.temporal.io/server/common/resolver" 43 ) 44 45 // Fixed namespace values for now 46 const ( 47 namespacePartition = 0 48 CassandraPersistenceName = "cassandra" 49 ) 50 51 const ( 52 templateCreateWorkflowExecutionStarted = `INSERT INTO open_executions (` + 53 `namespace_id, namespace_partition, workflow_id, run_id, start_time, execution_time, workflow_type_name, memo, encoding, task_queue) ` + 54 `VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` 55 56 templateDeleteWorkflowExecutionStarted = `DELETE FROM open_executions ` + 57 `WHERE namespace_id = ? ` + 58 `AND namespace_partition = ? ` + 59 `AND start_time = ? ` + 60 `AND run_id = ?` 61 62 templateCreateWorkflowExecutionClosed = `INSERT INTO closed_executions (` + 63 `namespace_id, namespace_partition, workflow_id, run_id, start_time, execution_time, close_time, workflow_type_name, status, history_length, memo, encoding, task_queue) ` + 64 `VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` 65 66 templateDeleteWorkflowExecutionClosed = `DELETE FROM closed_executions ` + 67 `WHERE namespace_id = ? ` + 68 `AND namespace_partition = ? ` + 69 `AND close_time = ? ` + 70 `AND run_id = ?` 71 72 templateGetOpenWorkflowExecutions = `SELECT workflow_id, run_id, start_time, execution_time, workflow_type_name, memo, encoding, task_queue ` + 73 `FROM open_executions ` + 74 `WHERE namespace_id = ? ` + 75 `AND namespace_partition = ? ` + 76 `AND start_time >= ? ` + 77 `AND start_time <= ? ORDER BY start_time desc` 78 79 templateGetOpenWorkflowExecutionsByType = `SELECT workflow_id, run_id, start_time, execution_time, workflow_type_name, memo, encoding, task_queue ` + 80 `FROM open_executions ` + 81 `WHERE namespace_id = ? ` + 82 `AND namespace_partition = ? ` + 83 `AND start_time >= ? ` + 84 `AND start_time <= ? ` + 85 `AND workflow_type_name = ? ` 86 87 templateGetOpenWorkflowExecutionsByID = `SELECT workflow_id, run_id, start_time, execution_time, workflow_type_name, memo, encoding, task_queue ` + 88 `FROM open_executions ` + 89 `WHERE namespace_id = ? ` + 90 `AND namespace_partition = ? ` + 91 `AND start_time >= ? ` + 92 `AND start_time <= ? ` + 93 `AND workflow_id = ? ` 94 95 templateGetOpenWorkflowExecutionByRunID = `SELECT workflow_id, run_id, start_time, execution_time, workflow_type_name, memo, encoding, task_queue ` + 96 `FROM open_executions ` + 97 `WHERE namespace_id = ? ` + 98 `AND namespace_partition = ? ` + 99 `AND start_time = ? ` + 100 `AND run_id = ? ` 101 102 templateGetClosedWorkflowExecutions = `SELECT workflow_id, run_id, start_time, execution_time, close_time, workflow_type_name, status, history_length, memo, encoding, task_queue ` + 103 `FROM closed_executions ` + 104 `WHERE namespace_id = ? ` + 105 `AND namespace_partition = ? ` + 106 `AND close_time >= ? ` + 107 `AND close_time <= ? ORDER BY close_time desc` 108 109 templateGetClosedWorkflowExecutionsByType = `SELECT workflow_id, run_id, start_time, execution_time, close_time, workflow_type_name, status, history_length, memo, encoding, task_queue ` + 110 `FROM closed_executions ` + 111 `WHERE namespace_id = ? ` + 112 `AND namespace_partition = ? ` + 113 `AND close_time >= ? ` + 114 `AND close_time <= ? ` + 115 `AND workflow_type_name = ? ` 116 117 templateGetClosedWorkflowExecutionsByID = `SELECT workflow_id, run_id, start_time, execution_time, close_time, workflow_type_name, status, history_length, memo, encoding, task_queue ` + 118 `FROM closed_executions ` + 119 `WHERE namespace_id = ? ` + 120 `AND namespace_partition = ? ` + 121 `AND close_time >= ? ` + 122 `AND close_time <= ? ` + 123 `AND workflow_id = ? ` 124 125 templateGetClosedWorkflowExecutionByRunID = `SELECT workflow_id, run_id, start_time, execution_time, close_time, workflow_type_name, status, history_length, memo, encoding, task_queue ` + 126 `FROM closed_executions ` + 127 `WHERE namespace_id = ? ` + 128 `AND namespace_partition = ? ` + 129 `AND close_time = ? ` + 130 `AND run_id = ? ` 131 132 templateGetClosedWorkflowExecutionsByStatus = `SELECT workflow_id, run_id, start_time, execution_time, close_time, workflow_type_name, status, history_length, memo, encoding, task_queue ` + 133 `FROM closed_executions ` + 134 `WHERE namespace_id = ? ` + 135 `AND namespace_partition = ? ` + 136 `AND close_time >= ? ` + 137 `AND close_time <= ? ` + 138 `AND status = ? ` 139 ) 140 141 type ( 142 visibilityStore struct { 143 session commongocql.Session 144 lowConslevel commongocql.Consistency 145 } 146 ) 147 148 var _ store.VisibilityStore = (*visibilityStore)(nil) 149 150 func NewVisibilityStore( 151 cfg config.Cassandra, 152 r resolver.ServiceResolver, 153 logger log.Logger, 154 metricsHandler metrics.Handler, 155 ) (*visibilityStore, error) { 156 session, err := commongocql.NewSession( 157 func() (*gocql.ClusterConfig, error) { 158 return commongocql.NewCassandraCluster(cfg, r) 159 }, 160 logger, 161 metricsHandler, 162 ) 163 if err != nil { 164 logger.Fatal("unable to initialize cassandra session", tag.Error(err)) 165 } 166 167 return &visibilityStore{ 168 session: session, 169 lowConslevel: commongocql.One, 170 }, nil 171 } 172 173 func (v *visibilityStore) GetName() string { 174 return CassandraPersistenceName 175 } 176 177 func (v *visibilityStore) GetIndexName() string { 178 // GetIndexName is used to get cluster metadata, which in verstions < v1.20 179 // were stored in an empty string key. 180 return "" 181 } 182 183 func (v *visibilityStore) ValidateCustomSearchAttributes( 184 searchAttributes map[string]any, 185 ) (map[string]any, error) { 186 return searchAttributes, nil 187 } 188 189 // Close releases the resources held by this object 190 func (v *visibilityStore) Close() { 191 v.session.Close() 192 } 193 194 func (v *visibilityStore) RecordWorkflowExecutionStarted( 195 ctx context.Context, 196 request *store.InternalRecordWorkflowExecutionStartedRequest, 197 ) error { 198 199 query := v.session.Query(templateCreateWorkflowExecutionStarted, 200 request.NamespaceID, 201 namespacePartition, 202 request.WorkflowID, 203 request.RunID, 204 persistence.UnixMilliseconds(request.StartTime), 205 persistence.UnixMilliseconds(request.ExecutionTime), 206 request.WorkflowTypeName, 207 request.Memo.Data, 208 request.Memo.EncodingType.String(), 209 request.TaskQueue, 210 ).WithContext(ctx) 211 // It is important to specify timestamp for all `open_executions` queries because 212 // we are using milliseconds instead of default microseconds. If custom timestamp collides with 213 // default timestamp, default one will always win because they are 1000 times bigger. 214 query = query.WithTimestamp(persistence.UnixMilliseconds(request.StartTime)) 215 err := query.Exec() 216 return commongocql.ConvertError("RecordWorkflowExecutionStarted", err) 217 } 218 219 func (v *visibilityStore) RecordWorkflowExecutionClosed( 220 ctx context.Context, 221 request *store.InternalRecordWorkflowExecutionClosedRequest, 222 ) error { 223 batch := v.session.NewBatch(commongocql.LoggedBatch).WithContext(ctx) 224 225 // First, remove execution from the open table 226 batch.Query(templateDeleteWorkflowExecutionStarted, 227 request.NamespaceID, 228 namespacePartition, 229 persistence.UnixMilliseconds(request.StartTime), 230 request.RunID, 231 ) 232 233 // Next, add a row in the closed table. 234 batch.Query(templateCreateWorkflowExecutionClosed, 235 request.NamespaceID, 236 namespacePartition, 237 request.WorkflowID, 238 request.RunID, 239 persistence.UnixMilliseconds(request.StartTime), 240 persistence.UnixMilliseconds(request.ExecutionTime), 241 persistence.UnixMilliseconds(request.CloseTime), 242 request.WorkflowTypeName, 243 request.Status, 244 request.HistoryLength, 245 request.Memo.Data, 246 request.Memo.EncodingType.String(), 247 request.TaskQueue, 248 ) 249 250 // RecordWorkflowExecutionStarted is using StartTime as the timestamp for every query in `open_executions` table. 251 // Due to the fact that cross DC using mutable state creation time as workflow start time and visibility using event time 252 // instead of last update time (https://github.com/uber/cadence/pull/1501) CloseTime can be before StartTime (or very close it). 253 // In this case, use (StartTime + minWorkflowDuration) for delete operation to guarantee that it is greater than StartTime 254 // and won't be ignored. 255 256 const minWorkflowDuration = time.Second 257 var batchTimestamp time.Time 258 if request.CloseTime.Sub(request.StartTime) < minWorkflowDuration { 259 batchTimestamp = request.StartTime.Add(minWorkflowDuration) 260 } else { 261 batchTimestamp = request.CloseTime 262 } 263 264 batch = batch.WithTimestamp(persistence.UnixMilliseconds(batchTimestamp)) 265 err := v.session.ExecuteBatch(batch) 266 return commongocql.ConvertError("RecordWorkflowExecutionClosed", err) 267 } 268 269 func (v *visibilityStore) UpsertWorkflowExecution( 270 _ context.Context, 271 _ *store.InternalUpsertWorkflowExecutionRequest, 272 ) error { 273 // Not OperationNotSupportedErr! 274 return nil 275 } 276 277 func (v *visibilityStore) ListOpenWorkflowExecutions( 278 ctx context.Context, 279 request *manager.ListWorkflowExecutionsRequest, 280 ) (*store.InternalListWorkflowExecutionsResponse, error) { 281 query := v.session.Query( 282 templateGetOpenWorkflowExecutions, 283 request.NamespaceID.String(), 284 namespacePartition, 285 persistence.UnixMilliseconds(request.EarliestStartTime), 286 persistence.UnixMilliseconds(request.LatestStartTime), 287 ).Consistency(v.lowConslevel).WithContext(ctx) 288 iter := query.PageSize(request.PageSize).PageState(request.NextPageToken).Iter() 289 290 response := &store.InternalListWorkflowExecutionsResponse{} 291 response.Executions = make([]*store.InternalWorkflowExecutionInfo, 0, request.PageSize) 292 wfexecution, has := readOpenWorkflowExecutionRecord(iter) 293 for has { 294 response.Executions = append(response.Executions, wfexecution) 295 wfexecution, has = readOpenWorkflowExecutionRecord(iter) 296 } 297 298 if len(iter.PageState()) > 0 { 299 response.NextPageToken = iter.PageState() 300 } 301 if err := iter.Close(); err != nil { 302 return nil, commongocql.ConvertError("ListOpenWorkflowExecutions", err) 303 } 304 return response, nil 305 } 306 307 func (v *visibilityStore) ListOpenWorkflowExecutionsByType( 308 ctx context.Context, 309 request *manager.ListWorkflowExecutionsByTypeRequest, 310 ) (*store.InternalListWorkflowExecutionsResponse, error) { 311 query := v.session.Query( 312 templateGetOpenWorkflowExecutionsByType, 313 request.NamespaceID.String(), 314 namespacePartition, 315 persistence.UnixMilliseconds(request.EarliestStartTime), 316 persistence.UnixMilliseconds(request.LatestStartTime), 317 request.WorkflowTypeName, 318 ).Consistency(v.lowConslevel).WithContext(ctx) 319 iter := query.PageSize(request.PageSize).PageState(request.NextPageToken).Iter() 320 321 response := &store.InternalListWorkflowExecutionsResponse{} 322 response.Executions = make([]*store.InternalWorkflowExecutionInfo, 0, request.PageSize) 323 wfexecution, has := readOpenWorkflowExecutionRecord(iter) 324 for has { 325 response.Executions = append(response.Executions, wfexecution) 326 wfexecution, has = readOpenWorkflowExecutionRecord(iter) 327 } 328 329 if len(iter.PageState()) > 0 { 330 response.NextPageToken = iter.PageState() 331 } 332 if err := iter.Close(); err != nil { 333 return nil, commongocql.ConvertError("ListOpenWorkflowExecutionsByType", err) 334 } 335 return response, nil 336 } 337 338 func (v *visibilityStore) ListOpenWorkflowExecutionsByWorkflowID( 339 ctx context.Context, 340 request *manager.ListWorkflowExecutionsByWorkflowIDRequest, 341 ) (*store.InternalListWorkflowExecutionsResponse, error) { 342 query := v.session.Query( 343 templateGetOpenWorkflowExecutionsByID, 344 request.NamespaceID.String(), 345 namespacePartition, 346 persistence.UnixMilliseconds(request.EarliestStartTime), 347 persistence.UnixMilliseconds(request.LatestStartTime), 348 request.WorkflowID, 349 ).Consistency(v.lowConslevel).WithContext(ctx) 350 iter := query.PageSize(request.PageSize).PageState(request.NextPageToken).Iter() 351 352 response := &store.InternalListWorkflowExecutionsResponse{} 353 response.Executions = make([]*store.InternalWorkflowExecutionInfo, 0, request.PageSize) 354 wfexecution, has := readOpenWorkflowExecutionRecord(iter) 355 for has { 356 response.Executions = append(response.Executions, wfexecution) 357 wfexecution, has = readOpenWorkflowExecutionRecord(iter) 358 } 359 360 if len(iter.PageState()) > 0 { 361 response.NextPageToken = iter.PageState() 362 } 363 if err := iter.Close(); err != nil { 364 return nil, commongocql.ConvertError("ListOpenWorkflowExecutionsByWorkflowID", err) 365 } 366 return response, nil 367 } 368 369 func (v *visibilityStore) ListClosedWorkflowExecutions( 370 ctx context.Context, 371 request *manager.ListWorkflowExecutionsRequest, 372 ) (*store.InternalListWorkflowExecutionsResponse, error) { 373 query := v.session.Query(templateGetClosedWorkflowExecutions, 374 request.NamespaceID.String(), 375 namespacePartition, 376 persistence.UnixMilliseconds(request.EarliestStartTime), 377 persistence.UnixMilliseconds(request.LatestStartTime), 378 ).Consistency(v.lowConslevel).WithContext(ctx) 379 iter := query.PageSize(request.PageSize).PageState(request.NextPageToken).Iter() 380 381 response := &store.InternalListWorkflowExecutionsResponse{} 382 response.Executions = make([]*store.InternalWorkflowExecutionInfo, 0, request.PageSize) 383 wfexecution, has := readClosedWorkflowExecutionRecord(iter) 384 for has { 385 response.Executions = append(response.Executions, wfexecution) 386 wfexecution, has = readClosedWorkflowExecutionRecord(iter) 387 } 388 389 if len(iter.PageState()) > 0 { 390 response.NextPageToken = iter.PageState() 391 } 392 if err := iter.Close(); err != nil { 393 return nil, commongocql.ConvertError("ListClosedWorkflowExecutions", err) 394 } 395 return response, nil 396 } 397 398 func (v *visibilityStore) ListClosedWorkflowExecutionsByType( 399 ctx context.Context, 400 request *manager.ListWorkflowExecutionsByTypeRequest, 401 ) (*store.InternalListWorkflowExecutionsResponse, error) { 402 query := v.session.Query( 403 templateGetClosedWorkflowExecutionsByType, 404 request.NamespaceID.String(), 405 namespacePartition, 406 persistence.UnixMilliseconds(request.EarliestStartTime), 407 persistence.UnixMilliseconds(request.LatestStartTime), 408 request.WorkflowTypeName, 409 ).Consistency(v.lowConslevel).WithContext(ctx) 410 iter := query.PageSize(request.PageSize).PageState(request.NextPageToken).Iter() 411 412 response := &store.InternalListWorkflowExecutionsResponse{} 413 response.Executions = make([]*store.InternalWorkflowExecutionInfo, 0, request.PageSize) 414 wfexecution, has := readClosedWorkflowExecutionRecord(iter) 415 for has { 416 response.Executions = append(response.Executions, wfexecution) 417 wfexecution, has = readClosedWorkflowExecutionRecord(iter) 418 } 419 420 if len(iter.PageState()) > 0 { 421 response.NextPageToken = iter.PageState() 422 } 423 if err := iter.Close(); err != nil { 424 return nil, commongocql.ConvertError("ListClosedWorkflowExecutionsByType", err) 425 } 426 return response, nil 427 } 428 429 func (v *visibilityStore) ListClosedWorkflowExecutionsByWorkflowID( 430 ctx context.Context, 431 request *manager.ListWorkflowExecutionsByWorkflowIDRequest, 432 ) (*store.InternalListWorkflowExecutionsResponse, error) { 433 query := v.session.Query(templateGetClosedWorkflowExecutionsByID, 434 request.NamespaceID.String(), 435 namespacePartition, 436 persistence.UnixMilliseconds(request.EarliestStartTime), 437 persistence.UnixMilliseconds(request.LatestStartTime), 438 request.WorkflowID, 439 ).Consistency(v.lowConslevel).WithContext(ctx) 440 iter := query.PageSize(request.PageSize).PageState(request.NextPageToken).Iter() 441 442 response := &store.InternalListWorkflowExecutionsResponse{} 443 response.Executions = make([]*store.InternalWorkflowExecutionInfo, 0, request.PageSize) 444 wfexecution, has := readClosedWorkflowExecutionRecord(iter) 445 for has { 446 response.Executions = append(response.Executions, wfexecution) 447 wfexecution, has = readClosedWorkflowExecutionRecord(iter) 448 } 449 450 if len(iter.PageState()) > 0 { 451 response.NextPageToken = iter.PageState() 452 } 453 if err := iter.Close(); err != nil { 454 return nil, commongocql.ConvertError("ListClosedWorkflowExecutionsByWorkflowID", err) 455 } 456 return response, nil 457 } 458 459 func (v *visibilityStore) ListClosedWorkflowExecutionsByStatus( 460 ctx context.Context, 461 request *manager.ListClosedWorkflowExecutionsByStatusRequest, 462 ) (*store.InternalListWorkflowExecutionsResponse, error) { 463 query := v.session.Query(templateGetClosedWorkflowExecutionsByStatus, 464 request.NamespaceID.String(), 465 namespacePartition, 466 persistence.UnixMilliseconds(request.EarliestStartTime), 467 persistence.UnixMilliseconds(request.LatestStartTime), 468 request.Status, 469 ).Consistency(v.lowConslevel).WithContext(ctx) 470 iter := query.PageSize(request.PageSize).PageState(request.NextPageToken).Iter() 471 472 response := &store.InternalListWorkflowExecutionsResponse{} 473 response.Executions = make([]*store.InternalWorkflowExecutionInfo, 0, request.PageSize) 474 wfexecution, has := readClosedWorkflowExecutionRecord(iter) 475 for has { 476 response.Executions = append(response.Executions, wfexecution) 477 wfexecution, has = readClosedWorkflowExecutionRecord(iter) 478 } 479 480 if len(iter.PageState()) > 0 { 481 response.NextPageToken = iter.PageState() 482 } 483 if err := iter.Close(); err != nil { 484 return nil, commongocql.ConvertError("ListClosedWorkflowExecutionsByStatus", err) 485 } 486 return response, nil 487 } 488 489 func (v *visibilityStore) DeleteWorkflowExecution( 490 ctx context.Context, 491 request *manager.VisibilityDeleteWorkflowExecutionRequest, 492 ) error { 493 var query commongocql.Query 494 if !request.StartTime.IsZero() { 495 query = v.session.Query(templateDeleteWorkflowExecutionStarted, 496 request.NamespaceID.String(), 497 namespacePartition, 498 persistence.UnixMilliseconds(request.StartTime), 499 request.RunID, 500 ).WithContext(ctx) 501 } else if !request.CloseTime.IsZero() { 502 query = v.session.Query(templateDeleteWorkflowExecutionClosed, 503 request.NamespaceID.String(), 504 namespacePartition, 505 persistence.UnixMilliseconds(request.CloseTime), 506 request.RunID, 507 ).WithContext(ctx) 508 } else { 509 panic("Cassandra visibility store: DeleteWorkflowExecution: both StartTime and CloseTime are nil") 510 } 511 512 if err := query.Exec(); err != nil { 513 return commongocql.ConvertError("DeleteWorkflowExecution", err) 514 } 515 return nil 516 } 517 518 func (v *visibilityStore) ListWorkflowExecutions( 519 _ context.Context, 520 _ *manager.ListWorkflowExecutionsRequestV2, 521 ) (*store.InternalListWorkflowExecutionsResponse, error) { 522 return nil, store.OperationNotSupportedErr 523 } 524 525 func (v *visibilityStore) ScanWorkflowExecutions( 526 _ context.Context, 527 _ *manager.ListWorkflowExecutionsRequestV2, 528 ) (*store.InternalListWorkflowExecutionsResponse, error) { 529 return nil, store.OperationNotSupportedErr 530 } 531 532 func (v *visibilityStore) CountWorkflowExecutions( 533 _ context.Context, 534 _ *manager.CountWorkflowExecutionsRequest, 535 ) (*manager.CountWorkflowExecutionsResponse, error) { 536 return nil, store.OperationNotSupportedErr 537 } 538 539 func (v *visibilityStore) GetWorkflowExecution( 540 ctx context.Context, 541 request *manager.GetWorkflowExecutionRequest, 542 ) (*store.InternalGetWorkflowExecutionResponse, error) { 543 if request.StartTime.IsZero() && request.CloseTime.IsZero() { 544 return nil, store.OperationNotSupportedErr 545 } 546 var wfexecution *store.InternalWorkflowExecutionInfo 547 var err error 548 if !request.CloseTime.IsZero() { 549 wfexecution, err = v.getClosedWorkflowExecution(ctx, request) 550 } else { 551 wfexecution, err = v.getOpenWorkflowExecution(ctx, request) 552 } 553 if err != nil { 554 return nil, err 555 } 556 return &store.InternalGetWorkflowExecutionResponse{ 557 Execution: wfexecution, 558 }, nil 559 } 560 561 func (v *visibilityStore) getOpenWorkflowExecution( 562 ctx context.Context, 563 request *manager.GetWorkflowExecutionRequest, 564 ) (*store.InternalWorkflowExecutionInfo, error) { 565 if request.StartTime.IsZero() { 566 return nil, store.OperationNotSupportedErr 567 } 568 query := v.session.Query( 569 templateGetOpenWorkflowExecutionByRunID, 570 request.NamespaceID.String(), 571 namespacePartition, 572 persistence.UnixMilliseconds(request.StartTime), 573 request.RunID, 574 ).Consistency(v.lowConslevel).WithContext(ctx) 575 iter := query.PageSize(1).Iter() 576 wfexecution, _ := readOpenWorkflowExecutionRecord(iter) 577 return wfexecution, nil 578 } 579 580 func (v *visibilityStore) getClosedWorkflowExecution( 581 ctx context.Context, 582 request *manager.GetWorkflowExecutionRequest, 583 ) (*store.InternalWorkflowExecutionInfo, error) { 584 if request.CloseTime.IsZero() { 585 return nil, store.OperationNotSupportedErr 586 } 587 query := v.session.Query( 588 templateGetClosedWorkflowExecutionByRunID, 589 request.NamespaceID.String(), 590 namespacePartition, 591 persistence.UnixMilliseconds(request.CloseTime), 592 request.RunID, 593 ).Consistency(v.lowConslevel).WithContext(ctx) 594 iter := query.PageSize(1).Iter() 595 wfexecution, _ := readClosedWorkflowExecutionRecord(iter) 596 return wfexecution, nil 597 } 598 599 func readOpenWorkflowExecutionRecord(iter commongocql.Iter) (*store.InternalWorkflowExecutionInfo, bool) { 600 var workflowID string 601 var runID string 602 var typeName string 603 var startTime time.Time 604 var executionTime time.Time 605 var memo []byte 606 var encoding string 607 var taskQueue string 608 if iter.Scan(&workflowID, &runID, &startTime, &executionTime, &typeName, &memo, &encoding, &taskQueue) { 609 record := &store.InternalWorkflowExecutionInfo{ 610 WorkflowID: workflowID, 611 RunID: runID, 612 TypeName: typeName, 613 StartTime: startTime, 614 ExecutionTime: executionTime, 615 Memo: persistence.NewDataBlob(memo, encoding), 616 TaskQueue: taskQueue, 617 Status: enumspb.WORKFLOW_EXECUTION_STATUS_RUNNING, 618 } 619 return record, true 620 } 621 return nil, false 622 } 623 624 func readClosedWorkflowExecutionRecord(iter commongocql.Iter) (*store.InternalWorkflowExecutionInfo, bool) { 625 var workflowID string 626 var runID string 627 var typeName string 628 var startTime time.Time 629 var executionTime time.Time 630 var closeTime time.Time 631 var status enumspb.WorkflowExecutionStatus 632 var historyLength int64 633 var memo []byte 634 var encoding string 635 var taskQueue string 636 if iter.Scan(&workflowID, &runID, &startTime, &executionTime, &closeTime, &typeName, &status, &historyLength, &memo, &encoding, &taskQueue) { 637 record := &store.InternalWorkflowExecutionInfo{ 638 WorkflowID: workflowID, 639 RunID: runID, 640 TypeName: typeName, 641 StartTime: startTime, 642 ExecutionTime: executionTime, 643 CloseTime: closeTime, 644 Status: status, 645 HistoryLength: historyLength, 646 Memo: persistence.NewDataBlob(memo, encoding), 647 TaskQueue: taskQueue, 648 } 649 return record, true 650 } 651 return nil, false 652 }