Skip to content

Commit cc8cf42

Browse files
authored
Cache tiler stac item queries (microsoft#251)
* Cache tiler stac item queries * Changes after testing * regenerate requirements * stac as pyproject.toml * clean up references to setup.py * format * Use same cache key between STAC and tiler * Do not write from tiler * fix the lines
1 parent ea2f92a commit cc8cf42

File tree

27 files changed

+300
-205
lines changed

27 files changed

+300
-205
lines changed

.flake8

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@ extend-ignore = E203, W503
44
exclude =
55
.git
66
__pycache__
7-
setup.py
87
.venv

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ After migrations and development database loading are in place, you can rebuild
8484
./scripts/update
8585
```
8686

87-
`pip` dependencies in `setup.py` are collected and installed through requirements files.
87+
`pip` dependencies in `pyproject.toml` are collected and installed through requirements files.
8888
If you modify dependencies, run `./scripts/generate-requirements` to regenerate
8989
`requirements-*.txt` used by Dockerfiles otherwise your dependency change will not
9090
be realized.

deployment/Dockerfile

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,44 @@
1-
FROM ubuntu:20.04
2-
3-
RUN apt-get update --fix-missing
4-
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y wget unzip curl gnupg \
5-
apt-transport-https \
6-
python3-pip \
1+
FROM mcr.microsoft.com/azurelinux/base/python:3.12
2+
3+
RUN tdnf install -y \
4+
ca-certificates \
5+
build-essential \
6+
tar \
7+
wget \
8+
unzip \
79
jq \
810
git \
9-
libicu66
11+
azure-cli \
12+
&& tdnf clean all
1013

1114
# Install Azure Function Tools
12-
13-
RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg
14-
RUN echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-focal-prod focal main" \
15-
> /etc/apt/sources.list.d/dotnetdev.list
16-
17-
RUN apt-get update && apt-get install -y azure-functions-core-tools-4
18-
19-
# Install Terraform 1.8.2
20-
21-
RUN wget -O terraform.zip https://releases.hashicorp.com/terraform/1.8.2/terraform_1.8.2_linux_amd64.zip
22-
RUN unzip terraform.zip
23-
RUN mv terraform /usr/local/bin
15+
RUN wget https://github.com/Azure/azure-functions-core-tools/releases/download/4.0.5700/Azure.Functions.Cli.linux-x64.4.0.5700.zip \
16+
&& unzip Azure.Functions.Cli.linux-x64.4.0.5700.zip -d /usr/local/azure-functions-core-tools-4 \
17+
&& chmod +x /usr/local/azure-functions-core-tools-4/func \
18+
&& chmod +x /usr/local/azure-functions-core-tools-4/gozip \
19+
&& ln -s /usr/local/azure-functions-core-tools-4/func /usr/local/bin/func \
20+
&& ln -s /usr/local/azure-functions-core-tools-4/gozip /usr/local/bin/gozip
21+
22+
# Install Terraform
23+
RUN wget -O terraform.zip https://releases.hashicorp.com/terraform/1.11.2/terraform_1.11.2_linux_amd64.zip \
24+
&& unzip terraform.zip \
25+
&& mv terraform /usr/local/bin
2426

2527
# Install kubectl
26-
27-
RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
28-
RUN install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
29-
28+
RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
29+
&& install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
3030

3131
# Install Helm
32-
33-
RUN curl https://baltocdn.com/helm/signing.asc | apt-key add -
34-
RUN echo "deb https://baltocdn.com/helm/stable/debian/ all main" | tee /etc/apt/sources.list.d/helm-stable-debian.list
35-
RUN apt-get update
36-
RUN apt-get install helm=3.14.0-1
32+
RUN wget https://get.helm.sh/helm-v3.14.4-linux-amd64.tar.gz \
33+
&& tar -zxvf helm-v3.14.4-linux-amd64.tar.gz \
34+
&& mv linux-amd64/helm /usr/local/bin/helm
3735

3836
# Install kubelogin
39-
40-
RUN curl -sL https://github.com/Azure/kubelogin/releases/download/v0.0.18/kubelogin-linux-amd64.zip --output kubelogin.zip \
37+
RUN curl -sL https://github.com/Azure/kubelogin/releases/download/v0.2.8/kubelogin-linux-amd64.zip --output kubelogin.zip \
4138
&& unzip -j kubelogin.zip bin/linux_amd64/kubelogin -d /usr/local/bin/ \
4239
&& rm -rf kubelogin.zip
4340

44-
# Install azure client
45-
RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash
46-
4741
# Install Jinja
48-
RUN pip3 install Jinja2 pyyaml==6.0
49-
42+
RUN pip install Jinja2 pyyaml==6.0.2
5043

5144
WORKDIR /opt/src

deployment/bin/deploy

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
176176
--wait \
177177
--timeout 2m0s \
178178
-f ${DEPLOY_VALUES_FILE} \
179+
--debug
179180

180181
echo "================"
181182
echo "==== Tiler ====="
@@ -188,6 +189,7 @@ if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
188189
--wait \
189190
--timeout 2m0s \
190191
-f ${DEPLOY_VALUES_FILE} \
192+
--debug
191193

192194
echo "=================="
193195
echo "==== Ingress ====="
@@ -199,7 +201,8 @@ if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
199201
--kube-context "${KUBE_CONTEXT}" \
200202
--wait \
201203
--timeout 2m0s \
202-
-f ${DEPLOY_VALUES_FILE}
204+
-f ${DEPLOY_VALUES_FILE} \
205+
--debug
203206

204207
echo "Installing ingress-nginx..."
205208
helm upgrade --install nginx-ingress helm/ingress-nginx-4.8.3.tgz \
@@ -215,7 +218,8 @@ if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
215218
--version "4.8.3"\
216219
--wait \
217220
--timeout 2m0s \
218-
-f bin/nginx-values.yaml
221+
-f bin/nginx-values.yaml \
222+
--debug
219223

220224
#########################
221225
# Deploy Azure Function #

deployment/terraform/resources/ai.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,10 @@ resource "azurerm_application_insights" "pc_application_insights" {
33
location = azurerm_resource_group.pc.location
44
resource_group_name = azurerm_resource_group.pc.name
55
application_type = "web"
6+
7+
lifecycle {
8+
ignore_changes = [
9+
workspace_id
10+
]
11+
}
612
}

docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ services:
117117

118118
redis:
119119
image: redis:6.2.6-buster
120-
command: redis-server --port 6380 --requirepass devcache
120+
command: redis-server --port 6380 --requirepass devcache --loglevel debug
121121
ports:
122122
- "6380:6380"
123123
volumes:

pccommon/pccommon/constants.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from opencensus.trace.attributes_helper import COMMON_ATTRIBUTES
44

5+
CACHE_KEY_ITEM = "/item"
6+
57
DEFAULT_COLLECTION_CONFIG_TABLE_NAME = "collectionconfig"
68
DEFAULT_CONTAINER_CONFIG_TABLE_NAME = "containerconfig"
79
DEFAULT_IP_EXCEPTION_CONFIG_TABLE_NAME = "ipexceptionlist"

pccommon/pccommon/redis.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from pccommon.config.core import PCAPIsConfig
1515
from pccommon.constants import (
1616
BACKPRESSURE_KEY_PREFIX,
17+
CACHE_KEY_ITEM,
1718
HTTP_429_TOO_MANY_REQUESTS,
1819
RATE_LIMIT_KEY_PREFIX,
1920
)
@@ -104,9 +105,15 @@ async def register_scripts(state: State) -> None:
104105

105106

106107
async def cached_result(
107-
fn: Callable[[], Coroutine[Any, Any, T]], cache_key: str, request: Request
108+
fn: Callable[[], Coroutine[Any, Any, T]],
109+
cache_key: str,
110+
request: Request,
111+
read_only: bool = False,
108112
) -> T:
109-
"""Either get the result from redis or run the function and cache the result."""
113+
"""Either get the result from redis or run the function and cache the result.
114+
115+
If `read_only` is True, only attempt to read from the cache, do not write to it.
116+
"""
110117
host = request.url.hostname
111118
host_cache_key = f"{cache_key}:{host}"
112119
settings = PCAPIsConfig.from_environment()
@@ -124,7 +131,7 @@ async def cached_result(
124131
except Exception as e:
125132
# Don't fail on redis failure
126133
logger.error(
127-
f"Error in cache: {e}",
134+
f"Error in cache read: {e}",
128135
extra=get_custom_dimensions({"cache_key": host_cache_key}, request),
129136
)
130137
if settings.debug:
@@ -139,14 +146,19 @@ async def cached_result(
139146
{"cache_key": host_cache_key, "duration": f"{te - ts:0.4f}"}, request
140147
),
141148
)
149+
if read_only:
150+
return result
151+
142152
try:
143153
if r:
144154
await r.set(host_cache_key, orjson.dumps(result), settings.redis_ttl)
145155
except Exception as e:
146156
# Don't fail on redis failure
147157
logger.error(
148-
f"Error in cache: {e}",
149-
extra=get_custom_dimensions({"cache_key": host_cache_key}, request),
158+
f"Error in cache write: {e}",
159+
extra=get_custom_dimensions(
160+
{"cache_key": host_cache_key, "cache_value_type": type(result)}, request
161+
),
150162
)
151163
if settings.debug:
152164
raise
@@ -321,3 +333,8 @@ async def _wrapper(*args: Any, **kwargs: Any) -> T:
321333
return _wrapper
322334

323335
return _decorator
336+
337+
338+
def stac_item_cache_key(collection: str, item: str) -> str:
339+
"""Generate a cache key for a STAC item."""
340+
return f"{CACHE_KEY_ITEM}:{collection}:{item}"

pcstac/pcstac/client.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,14 @@
1818

1919
from pccommon.config import get_all_render_configs, get_render_config
2020
from pccommon.config.collections import DefaultRenderConfig
21-
from pccommon.constants import DEFAULT_COLLECTION_REGION
21+
from pccommon.constants import CACHE_KEY_ITEM, DEFAULT_COLLECTION_REGION
2222
from pccommon.logging import get_custom_dimensions
23-
from pccommon.redis import back_pressure, cached_result, rate_limit
23+
from pccommon.redis import back_pressure, cached_result, rate_limit, stac_item_cache_key
2424
from pccommon.tracing import add_stac_attributes_from_search
2525
from pcstac.config import API_DESCRIPTION, API_LANDING_PAGE_ID, API_TITLE, get_settings
2626
from pcstac.contants import (
2727
CACHE_KEY_COLLECTION,
2828
CACHE_KEY_COLLECTIONS,
29-
CACHE_KEY_ITEM,
3029
CACHE_KEY_ITEMS,
3130
CACHE_KEY_LANDING_PAGE,
3231
CACHE_KEY_SEARCH,
@@ -288,7 +287,7 @@ async def _fetch() -> Item:
288287
)
289288
return item
290289

291-
cache_key = f"{CACHE_KEY_ITEM}:{collection_id}:{item_id}"
290+
cache_key = stac_item_cache_key(collection_id, item_id)
292291
return await cached_result(_fetch, cache_key, request)
293292

294293
@classmethod

pcstac/pcstac/contants.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
CACHE_KEY_COLLECTIONS = "/collections"
22
CACHE_KEY_COLLECTION = "/collection"
33
CACHE_KEY_ITEMS = "/items"
4-
CACHE_KEY_ITEM = "/item"
54
CACHE_KEY_QUERYABLES = "/queryables"
65
CACHE_KEY_SEARCH = "/search"
76
CACHE_KEY_LANDING_PAGE = "/landing-page"

0 commit comments

Comments
 (0)