[16.0] [IMP] fs_attachment: store attachments linked to different model/fields to different FS storages#269
Merged
OCA-git-bot merged 42 commits intoOCA:16.0from Aug 24, 2023
Conversation
a93e740 to
a954363
Compare
Using the base_attachment_object_storage module, the same way attachment_swift is done. Fixed a few issues along the way in attachment_swift.
When moving attachments from the filestore to an object storage, the filesystem files will be deleted only after the commit, so if the transaction is rollbacked, we still have the local files for another try.
Assume the following situation: * We have installed addons base, sale and attachment_s3 (hence base_attachment_object_storage as dependency) * All attachments are in S3 already * We run an upgrade of the 'base' addon, 'sale' is upgraded before attachment_s3 in the order of loading. * Sale updates the icon of the Sale menu * As attachment_s3 is not loaded yet, the attachment is created in the filestore Now if we don't persist the filestore or use different servers, we'll lose the images of the menus (or any attachment loaded by the install/upgrade of an addon). The implemented solution is to move the attachments from the filestore to the object storage at the loading of the module. However, this operation can take time and it shouldn't be run by 2 processes at the same time, so we want to detect if the module is loaded during a normal odoo startup or when some addons have been upgraded. There is nothing anymore at this point which allow us to know that modules just have been upgraded except... in the caller frame (load_modules). We have to rely on the inpect module and get the caller frame, which is not recommended, but seems the only way, besides, it's not called often and if _register_hook was called from another place, it would have no effect (unless the other place has a variable 'update_module' too).
The reason being: https://github.com/odoo/odoo/blob/9032617120138848c63b3cfa5d1913c5e5ad76db/odoo/addons/base/ir/ir_attachment.py#L344-L347 I nearly deleted this domain but it was too weird to be there for no reason. A comment explaining the issue was really missing.
Some attachments (e.g. image_small, image_medium) are stored in DB instead of the object storage for faster access. In some situations, we may have pushed all these files on the Object Storage (migration from a filesystem to object storage) and want to bring back these attachments from the object storage to the database. This method is not called anywhere but can be called by RPC or scripts.
The initial issue that triggered this rework is that the forced storage in
database was working only on writes, and was never applied on attachment
creations.
This feature is used to store small files that need to be read in a fast way in
database rather than in the object storage. Reading a file from the object
storage can take 150-200ms, which is fine for downloading a PDF file or a single
image, but not if you need 40 thumbnails.
Down the path to make a correction, I found that:
* the logic to force storage was called in `_inverse_datas`, which is not called
during a create
* odoo implemented a new method `_get_datas_related_values`, which is a model
method that receive only the data and the mimetype, and return the attachment
values and write the file to the correct place
The `_get_datas_related_values` is where we want to plug this special storage,
as it is called for create and write, and already handle the values and
conditional write. But using this method, we have less information than before
about the attachment, so let's review the different criterias we had before:
* res_model: we were using it to always store attachments related to
'ir.ui.view' in db, because assets are related to this model. However, we
don't really need to check this: we should store any javascript and css
documents in database.
* exclude res_model: we could have an exclusion list, to tell that for instance,
for mail.message, we should never store any image in db. We don't have this
information anymore, but I think it was never used and added "in case of".
Because the default configuration is "mail.mail" and "mail.message" and I
couldn't find any attachment with such res_model in any of our biggest
databases. So this is removed.
* mimetype and data (size) are the last criteria and we still have them
The new system is only based on mimetype and data size and I think it's actually
more versatile. Previously, we could set a global size and include mimetypes,
but we couldn't say "I want to store all images below 50KB and all files of type
X below 10KB". Now, we have a single system parameter with a dict configuration
(`ir_attachment.storage.force.database`) defaulting to:
{"image/": 51200, "application/javascript": 0, "text/css": 0}
Assets have a limit of zero, which means they will all be stored in the database
whatever their size is.
Overall, this is a great simplification of the module too, as the method
`_get_datas_related_values` integrates it better in the base calls of IrAttachment.
Note for upgrade:
I doubt we customized the previous system parameters which are now obsolete, but
if yes, the configuration may need to be moved to `ir_attachment.storage.force.database`.
For the record, the params were:
* mimetypes.list.storedb (default: image)
* file.maxsize.storedb (default: 51200)
* excluded.models.storedb (mail.message,mail.mail), no equivalent now
The method IrAttachment.force_storage_to_db_for_special_fields() should be called
through a migration script on existing databases to move the attachments back into
the database.
The main goal is to be able to easily do grep and sed when we do mass update on them
* fix: azure reading in stream monkey patch documents
a954363 to
593584c
Compare
593584c to
df278ca
Compare
Also fix typo into summary
Avoid recompute of new columns when installed on an existing database
Allows to provide configuration parameters through server environement files.
Remove code used to try to read file from the root filesystem and write into the specialized filesystem. This code was used to try to provide a way to manage staging environments by reusing the same filesystem storage but with a different directory_path depending of the environement. A simpler method is to configure use a different filesystem storage by environement. If a production database is restored in pre production env, you can declare a new filesystem storage with a different code to store the attachements by default and configure the filesystem storage from the production with information allowing to read documents stored in it but not to modify or delete existing documents. This make the implementation far more simple.
To create a new cursor, just ask to the current registry.... Loading a registry is very time consuming and could lead to deadlocks...
…ds to different FS storages
df278ca to
e493887
Compare
Contributor
|
/ocabot merge nobump |
Contributor
|
This PR looks fantastic, let's merge it! |
Contributor
|
Congratulations, your PR was merged at 7a53380. Thanks a lot for contributing to OCA. ❤️ |
|
I've encountered an issue with fs_attachment. After installation, I'm unable to create new attachments as it triggers the "_compute_internal_url" function, which crashes at the following line:
This occurs because the attachment initially lacks a name. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Supersedes #260 (This PR is part of the RFC #252 and depends on it.)
One may want to store attachments linked to different Odoo models/fields to different FS storages.
This is now possible: on the
fs.storageone just has to configure for which models / fields it will be the default storage.It is also possible to configure it in a server environment file, by giving a comma-separated list of models/fields XML ids.