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

Added experimental background job queue #20985

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open

Added experimental background job queue #20985

wants to merge 23 commits into from

Conversation

9larsons
Copy link
Contributor

ref ???

  • added background job queue behind config flags
  • when enabled, is only used for the member email analytics updates in order to speed up the parent job, and take load off of the main process that is serving requests

Added config flags for the job queue to make it switchable

config options are in services:jobs:queue and are 'enabled,reportStats,reportInterval,maxWorkers,logLevel(info/debug),pollMinInterval,pollMaxInterval,queueCapacity,fetchCount.
Copy link
Contributor

It looks like this PR contains a migration 👀
Here's the checklist for reviewing migrations:

General requirements

  • Satisfies idempotency requirement (both up() and down())
  • Does not reference models
  • Filename is in the correct format (and correctly ordered)
  • Targets the next minor version
  • All code paths have appropriate log messages
  • Uses the correct utils
  • Contains a minimal changeset
  • Does not mix DDL/DML operations
  • Tested in MySQL and SQLite

Schema changes

  • Both schema change and related migration have been implemented
  • For index changes: has been performance tested for large tables
  • For new tables/columns: fields use the appropriate predefined field lengths
  • For new tables/columns: field names follow the appropriate conventions
  • Does not drop a non-alpha table outside of a major version

Data changes

  • Mass updates/inserts are batched appropriately
  • Does not loop over large tables/datasets
  • Defends against missing or invalid data
  • For settings updates: follows the appropriate guidelines

@github-actions github-actions bot added the migration [pull request] Includes migration for review label Sep 12, 2024
@@ -985,7 +985,9 @@ module.exports = {
started_at: {type: 'dateTime', nullable: true},
finished_at: {type: 'dateTime', nullable: true},
created_at: {type: 'dateTime', nullable: false},
updated_at: {type: 'dateTime', nullable: true}
updated_at: {type: 'dateTime', nullable: true},
metadata: {type: 'text', maxlength: 1000000000, fieldtype: 'long', nullable: true},
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you have a sense of how big we'd expect this field to actually be? I wonder if allowing a maxlength this large is potentially encouraging misuse of this field?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I originally had it like other text fields at 2000 chars. I think that ought to be sufficient, but this is why I was holding off on the migration. We could start with 2000 and go from there?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah 2000 seems more sane to me — in most cases this should basically be a resource ID and maybe a couple small pieces of metadata (e.g. a timestamp or two, maybe a url pointing to a file or storage bucket, etc.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Cool, I'll bump back. Basically, since this is a 'JSON' field I had copied what we had elsewhere. Agree it seems to be overkill and it's easier to bump up than down.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Adjusted. If I mark this resolved, does it also resolve it for you? I forget how GH handles that.

@@ -42,7 +42,7 @@ const initTestMode = () => {
}, 5000);
};

const jobManager = new JobManager({errorHandler, workerMessageHandler, JobModel: models.Job, domainEvents});
const jobManager = new JobManager({errorHandler, workerMessageHandler, JobModel: models.Job, domainEvents, isDuplicate: true});
Copy link
Contributor

Choose a reason for hiding this comment

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

Not a blocker but just a note for future: it would be good to get to the bottom of why we need two instances of the job system, and ideally fix that so we don't need this anymore

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed! I've got a note to look into this because this is rather clunky way of handling it that I'm also really not a fan of.

*
* @returns {Promise<void>}
*/
async startQueueProcessor() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Just for the sake of readability and testability I think it might be good to break this bad boy up a bit, it's a little hard for me to follow in its current form.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did a pretty significant refactor of that entire class to break it up a lot, and expose more so testing is easier.

This is slightly less efficient - potentially - because we do a select before inserting instead of ignoring the insert conflict. It's likely less efficient because I don't anticipate a ton of duplicates, although the analytics job can certainly result in that, which is where I'd expect the knex implementation to slightly win out.

Regardless, testing is a fucking nightmare with knex directly as we have to spin up a db and use a schema for the table. Let's go down that path later if we need the performance improvements.
@9larsons
Copy link
Contributor Author

Need to add a couple integration tests then we ought to be ok. Not sure what the failure for Ghost-CLI is.

@vikaspotluri123
Copy link
Member

It looks like there's an error that's preventing the persisted logs from being printed 🙃 Here's the culprint:

Ghost was able to start, but errored during boot with: Cannot find module 'workerpool'

Looking at the lockfile changes, I'm not sure if they're intentional - there are a lot of new dependencies, which I think might stem from an older version of @tryghost/errors
Also, the real issue is that it looks like workerpool wasn't added as a dependency?

@9larsons
Copy link
Contributor Author

Ok, clearly there's some kind of race condition with the config mocks and initializing the service. I will have to look into that when I can reprioritize this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
migration [pull request] Includes migration for review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants