mirror of
https://git.sr.ht/~tsileo/microblog.pub
synced 2024-11-15 03:04:28 +00:00
Improve caching
This commit is contained in:
parent
2ee3fc0c67
commit
7237fbcc68
5 changed files with 106 additions and 37 deletions
97
app.py
97
app.py
|
@ -816,16 +816,41 @@ def paginated_query(db, q, limit=25, sort_key="_id"):
|
||||||
return outbox_data, older_than, newer_than
|
return outbox_data, older_than, newer_than
|
||||||
|
|
||||||
|
|
||||||
|
CACHING = True
|
||||||
|
|
||||||
|
|
||||||
|
def _get_cached(type_="html", arg=None):
|
||||||
|
if not CACHING:
|
||||||
|
return None
|
||||||
|
logged_in = session.get("logged_in")
|
||||||
|
if not logged_in:
|
||||||
|
cached = DB.cache2.find_one({"path": request.path, "type": type_, "arg": arg})
|
||||||
|
if cached:
|
||||||
|
app.logger.info("from cache")
|
||||||
|
return cached['response_data']
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _cache(resp, type_="html", arg=None):
|
||||||
|
if not CACHING:
|
||||||
|
return None
|
||||||
|
logged_in = session.get("logged_in")
|
||||||
|
if not logged_in:
|
||||||
|
DB.cache2.update_one(
|
||||||
|
{"path": request.path, "type": type_, "arg": arg},
|
||||||
|
{"$set": {"response_data": resp, "date": datetime.now(timezone.utc)}},
|
||||||
|
upsert=True,
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def index():
|
def index():
|
||||||
if is_api_request():
|
if is_api_request():
|
||||||
return jsonify(**ME)
|
return jsonify(**ME)
|
||||||
logged_in = session.get("logged_in", False)
|
cache_arg = f"{request.args.get('older_than', '')}:{request.args.get('newer_than', '')}"
|
||||||
if not logged_in:
|
cached = _get_cached("html", cache_arg)
|
||||||
cached = DB.cache.find_one({"path": request.path, "type": "html"})
|
if cached:
|
||||||
if cached:
|
return cached
|
||||||
app.logger.info("from cache")
|
|
||||||
return cached['response_data']
|
|
||||||
|
|
||||||
q = {
|
q = {
|
||||||
"box": Box.OUTBOX.value,
|
"box": Box.OUTBOX.value,
|
||||||
|
@ -859,12 +884,7 @@ def index():
|
||||||
newer_than=newer_than,
|
newer_than=newer_than,
|
||||||
pinned=pinned,
|
pinned=pinned,
|
||||||
)
|
)
|
||||||
if not logged_in:
|
_cache(resp, "html", cache_arg)
|
||||||
DB.cache.update_one(
|
|
||||||
{"path": request.path, "type": "html"},
|
|
||||||
{"$set": {"response_data": resp, "date": datetime.now(timezone.utc)}},
|
|
||||||
upsert=True,
|
|
||||||
)
|
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
|
@ -1011,32 +1031,41 @@ def note_by_id(note_id):
|
||||||
|
|
||||||
@app.route("/nodeinfo")
|
@app.route("/nodeinfo")
|
||||||
def nodeinfo():
|
def nodeinfo():
|
||||||
q = {
|
response = _get_cached("api")
|
||||||
"box": Box.OUTBOX.value,
|
cached = True
|
||||||
"meta.deleted": False, # TODO(tsileo): retrieve deleted and expose tombstone
|
if not response:
|
||||||
"type": {"$in": [ActivityType.CREATE.value, ActivityType.ANNOUNCE.value]},
|
cached = False
|
||||||
}
|
q = {
|
||||||
|
"box": Box.OUTBOX.value,
|
||||||
|
"meta.deleted": False, # TODO(tsileo): retrieve deleted and expose tombstone
|
||||||
|
"type": {"$in": [ActivityType.CREATE.value, ActivityType.ANNOUNCE.value]},
|
||||||
|
}
|
||||||
|
|
||||||
|
response = json.dumps(
|
||||||
|
{
|
||||||
|
"version": "2.0",
|
||||||
|
"software": {
|
||||||
|
"name": "microblogpub",
|
||||||
|
"version": f"Microblog.pub {VERSION}",
|
||||||
|
},
|
||||||
|
"protocols": ["activitypub"],
|
||||||
|
"services": {"inbound": [], "outbound": []},
|
||||||
|
"openRegistrations": False,
|
||||||
|
"usage": {"users": {"total": 1}, "localPosts": DB.activities.count(q)},
|
||||||
|
"metadata": {
|
||||||
|
"sourceCode": "https://github.com/tsileo/microblog.pub",
|
||||||
|
"nodeName": f"@{USERNAME}@{DOMAIN}",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if not cached:
|
||||||
|
_cache(response, "api")
|
||||||
return Response(
|
return Response(
|
||||||
headers={
|
headers={
|
||||||
"Content-Type": "application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.0#"
|
"Content-Type": "application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.0#"
|
||||||
},
|
},
|
||||||
response=json.dumps(
|
response=response,
|
||||||
{
|
|
||||||
"version": "2.0",
|
|
||||||
"software": {
|
|
||||||
"name": "microblogpub",
|
|
||||||
"version": f"Microblog.pub {VERSION}",
|
|
||||||
},
|
|
||||||
"protocols": ["activitypub"],
|
|
||||||
"services": {"inbound": [], "outbound": []},
|
|
||||||
"openRegistrations": False,
|
|
||||||
"usage": {"users": {"total": 1}, "localPosts": DB.activities.count(q)},
|
|
||||||
"metadata": {
|
|
||||||
"sourceCode": "https://github.com/tsileo/microblog.pub",
|
|
||||||
"nodeName": f"@{USERNAME}@{DOMAIN}",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -109,8 +109,8 @@ def create_indexes():
|
||||||
("activity.object.id", pymongo.ASCENDING),
|
("activity.object.id", pymongo.ASCENDING),
|
||||||
("meta.deleted", pymongo.ASCENDING),
|
("meta.deleted", pymongo.ASCENDING),
|
||||||
])
|
])
|
||||||
DB.cache.create_index([("path", pymongo.ASCENDING), ("type", pymongo.ASCENDING)])
|
DB.cache2.create_index([("path", pymongo.ASCENDING), ("type", pymongo.ASCENDING), ("arg", pymongo.ASCENDING)])
|
||||||
DB.cache.create_index("date", expireAfterSeconds=60)
|
DB.cache2.create_index("date", expireAfterSeconds=3600*12)
|
||||||
|
|
||||||
# Index for the block query
|
# Index for the block query
|
||||||
DB.activities.create_index(
|
DB.activities.create_index(
|
||||||
|
|
|
@ -1,5 +1,16 @@
|
||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
|
flower:
|
||||||
|
image: microblogpub:latest
|
||||||
|
links:
|
||||||
|
- mongo
|
||||||
|
- rabbitmq
|
||||||
|
command: 'celery flower -l info -A tasks --broker amqp://guest@rabbitmq// --address=0.0.0.0 --port=5556'
|
||||||
|
environment:
|
||||||
|
- MICROBLOGPUB_AMQP_BROKER=pyamqp://guest@rabbitmq//
|
||||||
|
- MICROBLOGPUB_MONGODB_HOST=mongo:27017
|
||||||
|
ports:
|
||||||
|
- "5556:5556"
|
||||||
celery:
|
celery:
|
||||||
image: microblogpub:latest
|
image: microblogpub:latest
|
||||||
links:
|
links:
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
python-dateutil
|
python-dateutil
|
||||||
libsass
|
libsass
|
||||||
|
flower
|
||||||
gunicorn
|
gunicorn
|
||||||
piexif
|
piexif
|
||||||
requests
|
requests
|
||||||
|
|
30
tasks.py
30
tasks.py
|
@ -6,6 +6,7 @@ import random
|
||||||
import requests
|
import requests
|
||||||
from celery import Celery
|
from celery import Celery
|
||||||
from little_boxes import activitypub as ap
|
from little_boxes import activitypub as ap
|
||||||
|
from little_boxes.errors import BadActivityError
|
||||||
from little_boxes.errors import ActivityGoneError
|
from little_boxes.errors import ActivityGoneError
|
||||||
from little_boxes.errors import ActivityNotFoundError
|
from little_boxes.errors import ActivityNotFoundError
|
||||||
from little_boxes.errors import NotAnActivityError
|
from little_boxes.errors import NotAnActivityError
|
||||||
|
@ -59,7 +60,8 @@ def process_new_activity(self, iri: str) -> None:
|
||||||
try:
|
try:
|
||||||
activity.get_object()
|
activity.get_object()
|
||||||
tag_stream = True
|
tag_stream = True
|
||||||
except NotAnActivityError:
|
except (NotAnActivityError, BadActivityError):
|
||||||
|
log.exception(f"failed to get announce object for {activity!r}")
|
||||||
# Most likely on OStatus notice
|
# Most likely on OStatus notice
|
||||||
tag_stream = False
|
tag_stream = False
|
||||||
should_delete = True
|
should_delete = True
|
||||||
|
@ -317,6 +319,26 @@ def post_to_inbox(activity: ap.BaseActivity) -> None:
|
||||||
finish_post_to_inbox.delay(activity.id)
|
finish_post_to_inbox.delay(activity.id)
|
||||||
|
|
||||||
|
|
||||||
|
def invalidate_cache(activity):
|
||||||
|
if activity.has_type(ap.ActivityType.LIKE):
|
||||||
|
if activity.get_object().id.startswith(BASE_URL):
|
||||||
|
DB.cache2.remove()
|
||||||
|
elif activity.has_type(ap.ActivityType.ANNOUNCE):
|
||||||
|
if activity.get_object.id.startswith(BASE_URL):
|
||||||
|
DB.cache2.remove()
|
||||||
|
elif activity.has_type(ap.ActivityType.UNDO):
|
||||||
|
DB.cache2.remove()
|
||||||
|
elif activity.has_type(ap.ActivityType.DELETE):
|
||||||
|
# TODO(tsileo): only invalidate if it's a delete of a reply
|
||||||
|
DB.cache2.remove()
|
||||||
|
elif activity.has_type(ap.ActivityType.UPDATE):
|
||||||
|
DB.cache2.remove()
|
||||||
|
elif activity.has_type(ap.ActivityType.CREATE):
|
||||||
|
note = activity.get_object()
|
||||||
|
if not note.inReplyTo or note.inReplyTo.startswith(ID):
|
||||||
|
DB.cache2.remove()
|
||||||
|
# FIXME(tsileo): check if it's a reply of a reply
|
||||||
|
|
||||||
@app.task(bind=True, max_retries=MAX_RETRIES) # noqa: C901
|
@app.task(bind=True, max_retries=MAX_RETRIES) # noqa: C901
|
||||||
def finish_post_to_inbox(self, iri: str) -> None:
|
def finish_post_to_inbox(self, iri: str) -> None:
|
||||||
try:
|
try:
|
||||||
|
@ -345,6 +367,10 @@ def finish_post_to_inbox(self, iri: str) -> None:
|
||||||
back.inbox_undo_announce(MY_PERSON, obj)
|
back.inbox_undo_announce(MY_PERSON, obj)
|
||||||
elif obj.has_type(ap.ActivityType.FOLLOW):
|
elif obj.has_type(ap.ActivityType.FOLLOW):
|
||||||
back.undo_new_follower(MY_PERSON, obj)
|
back.undo_new_follower(MY_PERSON, obj)
|
||||||
|
try:
|
||||||
|
invalidate_cache(activity)
|
||||||
|
except Exception:
|
||||||
|
log.exception("failed to invalidate cache")
|
||||||
except (ActivityGoneError, ActivityNotFoundError, NotAnActivityError):
|
except (ActivityGoneError, ActivityNotFoundError, NotAnActivityError):
|
||||||
log.exception(f"no retry")
|
log.exception(f"no retry")
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
@ -396,6 +422,8 @@ def finish_post_to_outbox(self, iri: str) -> None:
|
||||||
log.info(f"recipients={recipients}")
|
log.info(f"recipients={recipients}")
|
||||||
activity = ap.clean_activity(activity.to_dict())
|
activity = ap.clean_activity(activity.to_dict())
|
||||||
|
|
||||||
|
DB.cache2.remove()
|
||||||
|
|
||||||
payload = json.dumps(activity)
|
payload = json.dumps(activity)
|
||||||
for recp in recipients:
|
for recp in recipients:
|
||||||
log.debug(f"posting to {recp}")
|
log.debug(f"posting to {recp}")
|
||||||
|
|
Loading…
Reference in a new issue