Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CORE-133: Optimize SQL in billing account change synchronizer #3145

Merged
merged 3 commits into from
Dec 4, 2024

Conversation

davidangb
Copy link
Contributor

@davidangb davidangb commented Dec 3, 2024

Ticket: https://broadworkbench.atlassian.net/browse/CORE-133

Followup to #3139. In that other PR, we added a new STATUS column to the BILLING_ACCOUNT_CHANGES table, with logic to populate that column's values. We also added validation into the BillingAccountChangeSynchronizer which compares the polling query it currently uses to a prospective new query using the STATUS column. After running for a week or so, we verified that the business logic around STATUS is correct.

In this PR, we switch the BillingAccountChangeSynchronizer away from the current expensive polling query to the new optimized query using the STATUS column.

As a bonus, this PR also changes the BillingAccountChangeSynchronizer from running at a fixed rate via startTimerAtFixedRate to running at a fixed delay via startTimerWithFixedDelay. Instead of running every N seconds, we'll now wait N seconds between runs. The difference is that the former does not take into account how long the task runs, while the latter does.


PR checklist

  • Include the JIRA issue number in the PR description and title
  • Make sure Swagger is updated if API changes
    • ...and Orchestration's Swagger too!
  • If you changed anything in model/, then you should publish a new official rawls-model and update rawls-model in Orchestration's dependencies.
  • Get two thumbsworth of PR review
  • Verify all tests go green, including CI tests
  • Squash commits and merge to develop (branches are automatically deleted after merging)
  • Inform other teams of any substantial changes via Slack and/or email

@davidangb davidangb requested a review from a team as a code owner December 3, 2024 18:55
@davidangb davidangb requested review from samanehsan and trholdridge and removed request for a team December 3, 2024 18:55
@@ -540,6 +541,7 @@ trait RawlsBillingProjectComponent {
)
}

@VisibleForTesting
def getLastChange(billingProject: RawlsBillingProjectName): ReadAction[Option[BillingAccountChange]] =
BillingAccountChanges
.withProjectName(billingProject)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is now only used in tests, so I annotated it

.filter(_.id.in(latestChangeIds))
.sortBy(_.id.asc)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the old unoptimized query, now unused.

@@ -47,7 +46,7 @@ object BillingAccountChangeSynchronizer {
Behaviors.setup { context =>
val actor = BillingAccountChangeSynchronizer(dataSource, gcsDAO, samDAO)
Behaviors.withTimers { scheduler =>
scheduler.startTimerAtFixedRate(UpdateBillingAccounts, initialDelay, pollInterval)
scheduler.startTimerWithFixedDelay(UpdateBillingAccounts, initialDelay, pollInterval)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see https://doc.akka.io/japi/akka/snapshot/akka/actor/TimerScheduler.html for detailed explanation of the difference

BillingAccountChanges.latestChanges.unsynced
.take(1)
.result
BillingAccountChanges.nextOutstanding().result
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the core of the PR - changing from the old query to the new one

_ <- validateStatusColumn.recover { case e: Exception =>
logger.warn(s"BillingAccountChangeStatus logic failed with ${e.getMessage}", e)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we no longer need to validate the old query and new query return the same results, since we're getting rid of the old query

} yield changes shouldBe List(change1, change2).map(_.value)
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the old query is gone, so this test can go too

Copy link
Contributor

@trholdridge trholdridge left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Why is it better to take the task running time into account vs. just having them be "evenly spaced"?

@davidangb
Copy link
Contributor Author

Why is it better to take the task running time into account vs. just having them be "evenly spaced"?

@trholdridge imagine a task that runs for 7 seconds. If that task is scheduled via startTimerAtFixedRate at a fixed rate of 5 seconds, the system will try to start that task every 5 seconds. Since the first run of the task takes 7 seconds, the next run will start immediately, since it is already past the second run's start time. The third run will also start immediately, and so forth … resulting in a lot of load on the system because the task runs continuously.

However, if that task is scheduled via startTimerWithFixedDelay, it will run for 7 seconds, wait for 5 seconds, run for 7 seconds, run for 5, and so on. startTimerWithFixedDelay guarantees some downtime between tasks.

In this PR's use case of polling for billing account changes, we aren't worried about delays of a few seconds; we'll get to the change when we get to it. So, let's choose the scheduling approach that is lighter on the system. If we had strict latency requirements we might choose otherwise.

@davidangb davidangb merged commit 587aa68 into develop Dec 4, 2024
30 checks passed
@davidangb davidangb deleted the da_CORE-133_billingAccountChangeQuery branch December 4, 2024 14:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants