-
-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
251 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import models |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# Copyright 2024 Camptocamp SA | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
{ | ||
"name": "Endpoint cache", | ||
"summary": """Provide basic caching utils for endpoints""", | ||
"version": "14.0.1.0.0", | ||
"license": "LGPL-3", | ||
"development_status": "Alpha", | ||
"author": "Camptocamp, Odoo Community Association (OCA)", | ||
"maintainers": ["simahawk"], | ||
"website": "https://github.com/OCA/web-api", | ||
"depends": ["endpoint"], | ||
"data": ["views/endpoint_view.xml"], | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import endpoint_mixin |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# Copyright 2024 Camptocamp SA | ||
# @author: Simone Orsi <[email protected]> | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
from odoo import _, api, exceptions, fields, models | ||
from odoo.tools import date_utils | ||
|
||
from odoo.addons.http_routing.models.ir_http import slugify_one | ||
|
||
|
||
class EndpointMixin(models.AbstractModel): | ||
|
||
_inherit = "endpoint.mixin" | ||
|
||
cache_policy = fields.Selection( | ||
selection=[ | ||
("day", "Daily"), | ||
("week", "Weekly"), | ||
("month", "Monthly"), | ||
], | ||
default="day", | ||
) | ||
# cache_preheat = fields.Boolean() # TODO | ||
|
||
def _endpoint_cache_make_name(self, ext, suffix=None): | ||
parts = [ | ||
"endpoint_cache", | ||
slugify_one(self.name).replace("-", "_"), | ||
] | ||
if suffix: | ||
parts.append(suffix) | ||
if ext: | ||
parts.append(ext) | ||
return ".".join(parts) | ||
|
||
def _endpoint_cache_get(self, name): | ||
att = ( | ||
self.env["ir.attachment"] | ||
.sudo() | ||
.search(self._endpoint_cache_get_domain(name), limit=1) | ||
) | ||
self._logger.debug("_endpoint_cache_get found att=%s", att.id) | ||
return att.raw | ||
|
||
def _endpoint_cache_get_domain(self, cache_name): | ||
now = fields.Datetime.now() | ||
from_datetime = date_utils.start_of(now, self.cache_policy) | ||
to_datetime = date_utils.end_of(now, self.cache_policy) | ||
return [ | ||
("name", "=", cache_name), | ||
("res_model", "=", self._name), | ||
("res_id", "=", self.id), | ||
("create_date", ">=", from_datetime), | ||
("create_date", "<=", to_datetime), | ||
] | ||
|
||
def _endpoint_cache_store(self, name, raw_data, mimetype=None): | ||
self._logger.debug("_endpoint_cache_store store att=%s", name) | ||
if not name.startswith("endpoint_cache"): | ||
raise exceptions.UserError(_("Cache name must start with 'endpoint_cache'")) | ||
return ( | ||
self.env["ir.attachment"] | ||
.sudo() | ||
.create( | ||
{ | ||
"type": "binary", | ||
"name": name, | ||
"raw": raw_data, | ||
"mimetype": mimetype, | ||
"res_model": self._name, | ||
"res_id": self.id, | ||
} | ||
) | ||
) | ||
|
||
def _endpoint_cache_gc_domain(self, cache_name): | ||
now = fields.Datetime.now() | ||
gc_from = date_utils.subtract(now, days=30) | ||
return [ | ||
("name", "like", "endpoint_cache%"), | ||
("res_model", "=", self._name), | ||
("res_id", "=", self.id), | ||
("create_date", "<=", gc_from), | ||
] | ||
|
||
@api.autovacuum | ||
def _endpoint_cache_gc(self): | ||
"""Garbage collector for old caches""" | ||
self.env["ir.attachment"].sudo().search( | ||
self._endpoint_cache_gc_domain(self._name) | ||
).unlink() |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* Simone Orsi <[email protected]> |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Technical module provide basic caching configuration and utils for endpoints. |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* Add cache pre-heating |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
Example of usage in an endpoint:: | ||
|
||
.. code-block:: python | ||
# get the name of the cache | ||
cache_name = endpoint._make_cache_name("json") | ||
# check if the cache exists | ||
cached = endpoint._endpoint_cache_get(cache_name) | ||
if cached: | ||
result = cached | ||
else: | ||
result = json.dumps(env["my.model"]._get_a_very_expensive_computed_result()) | ||
# cache does not exist, create it0 | ||
endpoint._endpoint_cache_store(cache_name, result) | ||
resp = Response(result, content_type="application/json", status=200) | ||
result = dict(response=resp) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import test_endpoint |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# Copyright 2024 Camptocamp SA | ||
# @author: Simone Orsi <[email protected]> | ||
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). | ||
|
||
from freezegun import freeze_time | ||
|
||
from odoo import exceptions | ||
|
||
from odoo.addons.endpoint.tests.common import CommonEndpoint | ||
|
||
|
||
class TestEndpoint(CommonEndpoint): | ||
@classmethod | ||
def _setup_records(cls): | ||
super()._setup_records() | ||
cls.endpoint1 = cls.env.ref("endpoint.endpoint_demo_1") | ||
cls.endpoint2 = cls.env.ref("endpoint.endpoint_demo_2") | ||
|
||
def test_cache_name(self): | ||
self.assertEqual( | ||
self.endpoint1._endpoint_cache_make_name("json"), | ||
"endpoint_cache.demo_endpoint_1.json", | ||
) | ||
self.assertEqual( | ||
self.endpoint2._endpoint_cache_make_name("json"), | ||
"endpoint_cache.demo_endpoint_2.json", | ||
) | ||
|
||
def test_cache_store_bad_name(self): | ||
with self.assertRaisesRegex( | ||
exceptions.UserError, "Cache name must start with 'endpoint_cache'" | ||
): | ||
self.endpoint1._endpoint_cache_store("test", b"test") | ||
|
||
def test_cache_store_and_get(self): | ||
self.endpoint1._endpoint_cache_store("endpoint_cache.test", b"test") | ||
data = self.endpoint1._endpoint_cache_get("endpoint_cache.test") | ||
self.assertEqual(data, b"test") | ||
|
||
def test_cache_gc(self): | ||
dt1 = "2024-07-01 00:00:00" | ||
with freeze_time(dt1): | ||
cache1 = self.endpoint1._endpoint_cache_store( | ||
"endpoint_cache.test", b"test" | ||
) | ||
cache1._write( | ||
{ | ||
"create_date": dt1, | ||
} | ||
) | ||
dt2 = "2024-07-10 00:00:00" | ||
with freeze_time(dt2): | ||
cache2 = self.endpoint1._endpoint_cache_store( | ||
"endpoint_cache.test2", b"test2" | ||
) | ||
cache2._write( | ||
{ | ||
"create_date": dt2, | ||
} | ||
) | ||
dt2 = "2024-07-20 00:00:00" | ||
with freeze_time(dt2): | ||
cache3 = self.endpoint1._endpoint_cache_store( | ||
"endpoint_cache.test3", b"test3" | ||
) | ||
cache3._write( | ||
{ | ||
"create_date": dt2, | ||
} | ||
) | ||
with freeze_time("2024-08-01 00:00:00"): | ||
self.endpoint1._endpoint_cache_gc() | ||
self.assertFalse(cache1.exists()) | ||
self.assertTrue(cache2.exists()) | ||
self.assertTrue(cache3.exists()) | ||
with freeze_time("2024-08-12 00:00:00"): | ||
self.endpoint1._endpoint_cache_gc() | ||
self.assertFalse(cache1.exists()) | ||
self.assertFalse(cache2.exists()) | ||
self.assertTrue(cache3.exists()) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<!-- Copyright 2024 Camptocamp SA | ||
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). --> | ||
<odoo> | ||
|
||
<record model="ir.ui.view" id="endpoint_endpoint_form_view"> | ||
<field name="model">endpoint.endpoint</field> | ||
<field name="inherit_id" ref="endpoint.endpoint_endpoint_form_view" /> | ||
<field name="arch" type="xml"> | ||
<notebook> | ||
<page string="Cache"> | ||
<group> | ||
<field name="cache_policy" /> | ||
</group> | ||
<hr string="Cache usage example" /> | ||
<pre> | ||
# get the name of the cache | ||
cache_name = endpoint._make_cache_name("json") | ||
# check if the cache exists | ||
cached = endpoint._endpoint_cache_get(cache_name) | ||
if cached: | ||
result = cached | ||
else: | ||
result = json.dumps(env["my.model"]._get_a_very_expensive_computed_result()) | ||
# cache does not exist, create it0 | ||
endpoint._endpoint_cache_store(cache_name, result) | ||
resp = Response(result, content_type="application/json", status=200) | ||
result = dict(response=resp) | ||
</pre> | ||
</page> | ||
</notebook> | ||
</field> | ||
</record> | ||
|
||
</odoo> |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../../endpoint_cache |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import setuptools | ||
|
||
setuptools.setup( | ||
setup_requires=['setuptools-odoo'], | ||
odoo_addon=True, | ||
) |