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

gergo/previews #3765

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

gergo/previews #3765

wants to merge 11 commits into from

Conversation

gjedlicska
Copy link
Contributor

@gjedlicska gjedlicska commented Jan 6, 2025

Description & motivation

Limitations with the existing preview service:

  • The existing preview service worked by directly querying the database of the server. This blurred some segregation of responsibility between micro-services (and violated the database-per-microservice rule).
  • The preview service was given full read/write permissions to the database.
  • The preview service was limited to querying only one database, so each deployment required at least one dedicated preview-service.
  • As the preview-service requires significant allocation of memory and CPU, it is an expensive component. In low-traffic deployments it was not being fully utilised, resulting in unused & wasted resources. The cost-per-preview-generated was high and not optimal.
  • The preview service could not be run in a shared (one preview service for multiple deployment) mode because it required privileged access to each deployment.
  • The preview service could not easily be hosted on separate infrastructure because it required access to the database.
  • The preview service had to implement much of the objects API, duplicating the same in the server.
  • The preview service had limited or no unit tests.

This PR aims to resolve these shortcomings

Changes:

  • the preview frontend is now a new app, that exposes specific interface implementing functions via the window object, that we can use for easier integration testing of the viewer to the preview generation script
  • the preview service now does not have any access to the postgres DB, it gets a project scoped token in the job payload, and is now communicating with the preview frontend with the shared interface functions, so the app boundaries are now very clear and easy to understand
  • the server is responsible for storing the preview job results into the project specific regional DB-s
  • the server can rely on a dedicated redis queue for the preview jobs, and it specifies its own dedicated response queue. This allows us to run one dedicated cluster of preview services on a beefy gpu enabled machine, and they can generate previews for multiple server deployments securely

To-do before merge:

Screenshots:

Validation of changes:

Checklist:

  • My pull request follows the guidelines in the Contributing guide?
  • My pull request does not duplicate any other open Pull Requests for the same update/change?
  • My commits are related to the pull request and do not amend unrelated code or documentation.
  • My code follows a similar style to existing code.
  • I have added appropriate tests.
  • I have updated or added relevant documentation.

References

@gjedlicska gjedlicska requested a review from iainsproat January 6, 2025 13:50
@@ -125,4 +125,4 @@ RUN apt-get update && \
# Run everything after as non-privileged user.
USER pptruser

ENTRYPOINT [ "tini", "--", "node", "--loader=./dist/src/aliasLoader.js", "bin/www.js" ]
CMD [ "tini", "--", "node", "dist/main" ]
Copy link
Contributor

Choose a reason for hiding this comment

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

If we're changing this, and to be pedantic, entrypoint should be the binary being executed and cmd the arguments to that statement. So:

ENTRYPOINT [ "tini", "--", "node"]
CMD ["dist/main"]

And is there a reason for using dist/main pattern over the bin/www.js pattern?

Copy link
Contributor

Choose a reason for hiding this comment

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

What's the _bak directory? Is it a backup to be removed?

@@ -1,4 +1,4 @@
import type { Preview } from '@/domain/domain.js'
import type { Preview } from '../domain/domain.js'
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we retain the alias pattern please? i.e. @/domain/domain.js would be preferable.

@@ -12,7 +12,7 @@ import {
notifyUpdateFactory,
updatePreviewMetadataFactory
} from '@/repositories/objectPreview.js'
import { insertPreviewFactory } from '@/repositories/previews.js'
import { insertPreviewFactory } from '../repositories/previews.js'
Copy link
Contributor

Choose a reason for hiding this comment

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

Again, the alias pattern should be used.

import type { InsertPreview } from '@/repositories/previews.js'
import type { GeneratePreview } from '../clients/previewService.js'
import type { Angle, ObjectIdentifier, PreviewId } from '../domain/domain.js'
import type { InsertPreview } from '../repositories/previews.js'
Copy link
Contributor

Choose a reason for hiding this comment

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

alias pattern should be used. Is there an eslint rule missing?

}
}
}
const previewRequestQueue = new Bull('preview-service-jobs', opts)
Copy link
Contributor

Choose a reason for hiding this comment

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

The queue name should be configurable.


const opts = {
// redisOpts here will contain at least a property of connectionName which will identify the queue based on its name
createClient: function (type: string, redisOpts: RedisOptions) {
Copy link
Contributor

Choose a reason for hiding this comment

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

In the case of one worker for multiple deployments, how do we expect the infrastructure to be configured?

A new Redis cluster with one preview service queue? And all deployments publish to the cluster & queue.
Or the preview-service connects to all the existing Redis clusters, and reads each of their queues?


if (isInitial) {
listenFor('preview_generation_update', messageProcessor)
// listenFor('preview_generation_update', messageProcessor)
Copy link
Contributor

Choose a reason for hiding this comment

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

should remove all commented out code. ☠️


app.options('/preview/:streamId/:angle?', cors())
app.get('/preview/:streamId/:angle?', cors(), async (req, res) => {
const projectDb = await getProjectDbClient({ projectId: req.params.streamId })
Copy link
Contributor

Choose a reason for hiding this comment

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

How do we feel about refactoring these to named functions (possibly exported from the services directory?), so they can be called from other parts of the server codebase without an http call (or tested without starting an Express server)?

@@ -85,6 +86,7 @@
"graphql-subscriptions": "^2.0.0",
"graphql-tag": "^2.12.6",
"ioredis": "^5.2.2",
"join-images": "^1.1.5",
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think the server should be responsible for joining images.

@iainsproat
Copy link
Contributor

.github/workflows/preview-service-acceptance.yml should also be deleted if we're (temporarily, hopefully) removing the acceptance test.

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.

2 participants