-
-
Notifications
You must be signed in to change notification settings - Fork 347
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
Fixes an import error when using S3/Minio with no redis #1224
Conversation
Hmm, I think it may be possible to repeat the HostedStorageManager tests with REDIS_URL or TEST_REDIS_URL turned off, in which case S3/minio would still be used but Redis would be unavailable. But maybe it wouldn't even have caught this problem... |
This does seem doable, but the tests in the file don't exercise importing so they pass without this fix. Hmm test/nbrowser/Importer.ts fails quickly if run again S3 and not Redis, then succeeds if your fix is applied. It is maybe a bit excessive to run a whole new copy of all browser tests under this condition, but @Spoffy do you think it would be worth adding a clause in .github/workflows/main.yml to add test/nbrowser/Importer.ts to one of the runs, running it with S3 and with/without Redis? Or maybe there is a unit-like test that needs adding to HostedStorageManager, and have that do a run (say of |
Error is caused due to these steps: - File is uploaded to Home server and attempts to import - Import ends up in `claimDocument` in `HostedStorageManager` - Tries to read doc metadata from DocWorkerMap, gets 'unknown' as md5 hash - Thinks local doc is out of date and erases it. - Downloads a non-existent file from S3, so import fails as it has no data. This fixes it by checking for DummyDocWorker's special 'unknown' MD5, forcing an S3 check.
5680d1f
to
189aea5
Compare
Added some tests that cover this change. I also altered the constructors for HostedMetadataManager and HostedStorageManager to simplify mocking when testing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the test! Some small comments.
@@ -638,6 +638,7 @@ export class DocManager extends EventEmitter { | |||
throw new Error('Grist docs must be uploaded individually'); | |||
} | |||
const first = uploadInfo.files[0].origName; | |||
log.debug(`DocManager._doImportDoc: Received doc with name ${first}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any context that can be added here? For example, what user this is on behalf of, the team site, anything like that. Otherwise this isn't very helpful in prod, though I can see how it could be useful to you while you work on this change. Admittedly your log messages are consistent with the style in other parts of DocManager
, but for new messages it would be great to get closer to what new messages in ActiveDoc
do, see uses of this.getLogMeta(docSession)
there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think my main goal for leaving this in, was to know when a file was traveling along the import route.
I'll see if I can workspace / org / userId context? Up to you if this is worth having in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thing is without the context these kinds of logs are mostly useless in prod because they are mixed in with tons of parallel activity. Some kind of context can help you filter, or piece a narrative together. Still, not going to insist on it.
import log from 'app/server/lib/log'; | ||
|
||
export type SetDocsMetadataFunc = (metadata: { [p: string]: DocumentMetadata }) => Promise<any>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment on what this type is for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a comment, and slightly renamed the type for a bit more clarity.
@@ -52,6 +52,11 @@ function checkValidDocId(docId: string): void { | |||
} | |||
} | |||
|
|||
export interface HostedStorageCallbacks { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment on what this interface is for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added comments to the individual functions, as I was struggling to come up with a comment for this that wasn't just a paraphrased explanation of dependency injection. Open to suggestions on this!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to add the comment though.
I don't understand why dbManager is not enough. What other things can change that behavior (with links).
@@ -33,6 +33,7 @@ import {createTmpDir, getGlobalPluginManager} from 'test/server/docTools'; | |||
import {EnvironmentSnapshot, setTmpLogLevel, useFixtureDoc} from 'test/server/testUtils'; | |||
import {waitForIt} from 'test/server/wait'; | |||
import uuidv4 from "uuid/v4"; | |||
import {IDocWorkerMap} from "app/server/lib/DocWorkerMap"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As much as possible, try to order imports alphabetically, and use the local quote style (I realize it is already inconsistent in this file)
tmpDir = await createTmpDir(); | ||
oldEnv = new EnvironmentSnapshot(); | ||
// Disable Redis | ||
delete process.env.REDIS_URL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's also a TEST_REDIS_URL
I see mentioned in code, might that need wiping too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That should be fine - TEST_REDIS_URL seems to be used explicitly by other tests to configure where to connect to.
All we care about here is making sure we get DummyDocWorker out of getDocWorkerMap
, which removing process.env.REDIS_URL
is sufficient to do. 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm afraid it gets set in test/testrun.sh in SaaS tests :( but yes it would be ok to deal with that if tests arrive there and are failing.
|
||
const creator = create?.getStorageOptions?.('minio')?.create; | ||
if (!creator) { | ||
return this.skip(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm this won't skip if minio is not configured. What do you think about something like:
const storage = create?.getStorageOptions?.('minio');
const creator = storage?.create;
if (!creator || !storage?.check?.()) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @Spoffy
Context
Error is caused due to these steps:
claimDocument
inHostedStorageManager
Proposed solution
This fixes it by checking for DummyDocWorker's special 'unknown' MD5, forcing an S3 check.
Related issues
https://community.getgrist.com/t/no-metadata-for-imported-grist-document/6029/32
Has this been tested?
Yes locally, but we don't have a CI/CD setup for S3 with no redis currently.