quickbase-extract 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/.editorconfig +0 -8
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/.gitignore +0 -9
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/CHANGELOG.md +34 -0
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/PKG-INFO +193 -57
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/README.md +192 -56
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/pyproject.toml +1 -1
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/src/quickbase_extract/__init__.py +12 -2
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/src/quickbase_extract/api_handlers.py +5 -3
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/src/quickbase_extract/cache_manager.py +6 -0
- quickbase_extract-0.3.0/src/quickbase_extract/cache_sync.py +191 -0
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/tests/conftest.py +19 -0
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/tests/test_api_handlers.py +22 -3
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/tests/test_cache_manager.py +127 -32
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/tests/test_cache_orchestration.py +2 -0
- quickbase_extract-0.3.0/tests/test_cache_sync.py +360 -0
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/tests/test_report_data.py +13 -2
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/tests/test_report_metadata.py +2 -0
- quickbase_extract-0.2.0/src/quickbase_extract/cache_sync.py +0 -94
- quickbase_extract-0.2.0/tests/test_cache_sync.py +0 -117
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/.pre-commit-config.yaml +0 -0
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/.python-version +0 -0
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/LICENSE.txt +0 -0
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/TODO.md +0 -0
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/src/quickbase_extract/cache_orchestration.py +0 -0
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/src/quickbase_extract/config.py +0 -0
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/src/quickbase_extract/py.typed +0 -0
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/src/quickbase_extract/report_data.py +0 -0
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/src/quickbase_extract/report_metadata.py +0 -0
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/src/quickbase_extract/utils.py +0 -0
- {quickbase_extract-0.2.0 → quickbase_extract-0.3.0}/tests/test_utils.py +0 -0
|
@@ -20,14 +20,6 @@ indent_style = space
|
|
|
20
20
|
indent_size = 4
|
|
21
21
|
max_line_length = 120
|
|
22
22
|
|
|
23
|
-
# ============================================================
|
|
24
|
-
# JavaScript / TypeScript
|
|
25
|
-
# ============================================================
|
|
26
|
-
[*.{js,jsx,ts,tsx}]
|
|
27
|
-
indent_style = space
|
|
28
|
-
indent_size = 2
|
|
29
|
-
max_line_length = 120
|
|
30
|
-
|
|
31
23
|
# ============================================================
|
|
32
24
|
# JSON
|
|
33
25
|
# ============================================================
|
|
@@ -5,6 +5,40 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.3.0] - 2026-04-27
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `complete_cache_refresh()` function in `cache_sync` module for selective cache refresh in development
|
|
13
|
+
- Support for granular cache refresh control:
|
|
14
|
+
- `force_all=True`: Refresh both metadata and data caches
|
|
15
|
+
- `force_metadata=True`: Refresh only metadata cache
|
|
16
|
+
- `force_data=True`: Refresh only data cache
|
|
17
|
+
- Cache refresh workflow: clear /tmp → fetch fresh from Quickbase → update S3 → re-sync to /tmp
|
|
18
|
+
- Manual development toggles in Lambda handlers for testing cache refresh without API changes
|
|
19
|
+
- Comprehensive test suite for complete cache refresh functionality
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Lambda workers can now force complete cache refresh for development/debugging by toggling code variables
|
|
24
|
+
- Cache refresh strategy clarified: selective refresh based on what changed (metadata vs data)
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Dev workflow now supports forcing cache refresh without modifying Lambda event API
|
|
29
|
+
- Ensures /tmp and S3 are synchronized after cache refresh operations
|
|
30
|
+
|
|
31
|
+
## [0.2.1] - 2026-04-25
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- `sync_from_s3()` now preserves S3 `LastModified` timestamps via `os.utime()`, so `get_cache_age_hours()` returns accurate ages after S3 restore (previously always returned ~0 on Lambda cold start)
|
|
36
|
+
- Renamed misleading `should_sync` variable to `already_synced` in `sync_from_s3_once()` for clarity
|
|
37
|
+
|
|
38
|
+
### Removed
|
|
39
|
+
|
|
40
|
+
- `FORCE_CACHE_REFRESH` environment variable support from `sync_from_s3_once()` — use `force=True` parameter instead
|
|
41
|
+
|
|
8
42
|
## [0.2.0] - 2026-04-22
|
|
9
43
|
|
|
10
44
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quickbase-extract
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Extract and cache Quickbase report data with built-in error handling and S3 support
|
|
5
5
|
Project-URL: Homepage, https://github.com/tbrezler/quickbase-extract
|
|
6
6
|
Project-URL: Repository, https://github.com/tbrezler/quickbase-extract.git
|
|
@@ -882,7 +882,6 @@ s3://mit-bio-quickbase/my_project/dev/cache/report_metadata/...
|
|
|
882
882
|
| `CACHE_BUCKET` | S3 bucket for Lambda cache | - |
|
|
883
883
|
| `METADATA_STALE_HOURS` | Threshold (hours) for metadata cache staleness | `168` (7 days) |
|
|
884
884
|
| `DATA_STALE_HOURS` | Threshold (hours) for data cache staleness | `24` (1 day) |
|
|
885
|
-
| `FORCE_CACHE_REFRESH` | If set to "true", forces cache refresh on next sync | - |
|
|
886
885
|
|
|
887
886
|
### Custom Cache Location
|
|
888
887
|
|
|
@@ -956,10 +955,30 @@ def lambda_handler(event, context):
|
|
|
956
955
|
- Cold start: Syncs cache from S3
|
|
957
956
|
- Cache freshness: Auto-refreshes if stale
|
|
958
957
|
- Data fetching: Queries Quickbase and caches results
|
|
958
|
+
- Development: Supports forcing complete cache refresh for testing
|
|
959
959
|
"""
|
|
960
960
|
client = get_client()
|
|
961
961
|
cache_mgr = get_cache_manager()
|
|
962
962
|
|
|
963
|
+
# OPTIONAL: Set to True to force cache refresh (for development/debugging only)
|
|
964
|
+
# Only one should be True at a time. force_all overrides the others.
|
|
965
|
+
FORCE_COMPLETE_CACHE_REFRESH_ALL = False
|
|
966
|
+
FORCE_COMPLETE_CACHE_REFRESH_METADATA = False
|
|
967
|
+
FORCE_COMPLETE_CACHE_REFRESH_DATA = False
|
|
968
|
+
|
|
969
|
+
# Force complete cache refresh if needed (dev/debugging only)
|
|
970
|
+
if (FORCE_COMPLETE_CACHE_REFRESH_ALL or FORCE_COMPLETE_CACHE_REFRESH_METADATA
|
|
971
|
+
or FORCE_COMPLETE_CACHE_REFRESH_DATA):
|
|
972
|
+
from quickbase_extract import complete_cache_refresh
|
|
973
|
+
complete_cache_refresh(
|
|
974
|
+
cache_manager=cache_mgr,
|
|
975
|
+
client=client,
|
|
976
|
+
report_configs=get_all_reports(),
|
|
977
|
+
force_all=FORCE_COMPLETE_CACHE_REFRESH_ALL,
|
|
978
|
+
force_metadata=FORCE_COMPLETE_CACHE_REFRESH_METADATA,
|
|
979
|
+
force_data=FORCE_COMPLETE_CACHE_REFRESH_DATA,
|
|
980
|
+
)
|
|
981
|
+
|
|
963
982
|
# Step 1: Sync cache from S3 on cold start (only on first invocation)
|
|
964
983
|
sync_from_s3_once(cache_mgr)
|
|
965
984
|
|
|
@@ -1265,7 +1284,6 @@ Checks metadata and data caches independently. Refreshes only the caches that ar
|
|
|
1265
1284
|
**Environment Variables:**
|
|
1266
1285
|
- `METADATA_STALE_HOURS`: Override default metadata staleness threshold (in hours)
|
|
1267
1286
|
- `DATA_STALE_HOURS`: Override default data staleness threshold (in hours)
|
|
1268
|
-
- `FORCE_ALL_CACHE_REFRESH`: Set to "true" to force refresh regardless of cache state
|
|
1269
1287
|
|
|
1270
1288
|
**Returns:** None
|
|
1271
1289
|
|
|
@@ -1565,6 +1583,48 @@ def lambda_handler(event, context):
|
|
|
1565
1583
|
metadata = load_report_metadata_batch(cache_mgr, config)
|
|
1566
1584
|
```
|
|
1567
1585
|
|
|
1586
|
+
#### `complete_cache_refresh(cache_manager, client, report_configs, force_all=False, force_metadata=False, force_data=False)`
|
|
1587
|
+
|
|
1588
|
+
Completely refresh cache for development/debugging: clear /tmp, fetch fresh from Quickbase, update S3, re-sync to /tmp.
|
|
1589
|
+
|
|
1590
|
+
This is a development utility for forcing a complete cache refresh when report metadata or configurations change. Clears local /tmp cache, fetches fresh data from Quickbase, writes to S3, and re-syncs to /tmp.
|
|
1591
|
+
|
|
1592
|
+
**Parameters:**
|
|
1593
|
+
- `cache_manager` (CacheManager): Cache manager instance
|
|
1594
|
+
- `client`: Quickbase API client for fetching fresh data
|
|
1595
|
+
- `report_configs` (list[ReportConfig]): List of all ReportConfig instances to refresh
|
|
1596
|
+
- `force_all` (bool): If True, refresh both metadata and data. Defaults to False.
|
|
1597
|
+
- `force_metadata` (bool): If True (and `force_all` is False), refresh only metadata. Defaults to False.
|
|
1598
|
+
- `force_data` (bool): If True (and `force_all` is False), refresh only data. Defaults to False.
|
|
1599
|
+
|
|
1600
|
+
**Returns:** None
|
|
1601
|
+
|
|
1602
|
+
**Raises:**
|
|
1603
|
+
- `Exception`: If cache clearing or refresh operations fail
|
|
1604
|
+
|
|
1605
|
+
**Example:**
|
|
1606
|
+
```python
|
|
1607
|
+
from quickbase_extract import complete_cache_refresh
|
|
1608
|
+
|
|
1609
|
+
# Refresh only metadata (after changing report configurations)
|
|
1610
|
+
complete_cache_refresh(
|
|
1611
|
+
cache_manager=cache_mgr,
|
|
1612
|
+
client=qb_client,
|
|
1613
|
+
report_configs=get_all_reports(),
|
|
1614
|
+
force_metadata=True
|
|
1615
|
+
)
|
|
1616
|
+
|
|
1617
|
+
# Refresh all (metadata + data)
|
|
1618
|
+
complete_cache_refresh(
|
|
1619
|
+
cache_manager=cache_mgr,
|
|
1620
|
+
client=qb_client,
|
|
1621
|
+
report_configs=get_all_reports(),
|
|
1622
|
+
force_all=True
|
|
1623
|
+
)
|
|
1624
|
+
```
|
|
1625
|
+
|
|
1626
|
+
**Note:** This function is designed for development/debugging. To use in Lambda, add toggles to your handler (see "Development/Debug Mode" section below).
|
|
1627
|
+
|
|
1568
1628
|
### Query Execution with Retry Logic
|
|
1569
1629
|
|
|
1570
1630
|
#### `handle_query(client, table_id, *, select=None, where=None, sort_by=None, group_by=None, options=None, description="", max_retries=3)`
|
|
@@ -2108,43 +2168,6 @@ fields = info["fields"]
|
|
|
2108
2168
|
|
|
2109
2169
|
---
|
|
2110
2170
|
|
|
2111
|
-
### Issue: "FORCE_CACHE_REFRESH not working"
|
|
2112
|
-
|
|
2113
|
-
**Symptom:** Set `FORCE_CACHE_REFRESH=true` but cache still not refreshing.
|
|
2114
|
-
|
|
2115
|
-
**Cause:** Environment variable case-sensitive or not set correctly.
|
|
2116
|
-
|
|
2117
|
-
**Solution:**
|
|
2118
|
-
|
|
2119
|
-
1. **Verify env var is set (case-sensitive):**
|
|
2120
|
-
```bash
|
|
2121
|
-
# Must be exactly this (uppercase)
|
|
2122
|
-
export FORCE_ALL_CACHE_REFRESH=true
|
|
2123
|
-
|
|
2124
|
-
# Not these (wrong):
|
|
2125
|
-
export force_cache_refresh=true
|
|
2126
|
-
export Force_Cache_Refresh=true
|
|
2127
|
-
```
|
|
2128
|
-
|
|
2129
|
-
2. **Verify it's being read:**
|
|
2130
|
-
```python
|
|
2131
|
-
import os
|
|
2132
|
-
print(os.environ.get("FORCE_ALL_CACHE_REFRESH")) # Should print "true"
|
|
2133
|
-
```
|
|
2134
|
-
|
|
2135
|
-
3. **Use programmatic force instead:**
|
|
2136
|
-
```python
|
|
2137
|
-
ensure_cache_freshness(
|
|
2138
|
-
client=client,
|
|
2139
|
-
cache_manager=cache_mgr,
|
|
2140
|
-
report_configs_all=get_all_reports(),
|
|
2141
|
-
report_configs_to_cache=get_reports_to_cache(),
|
|
2142
|
-
force_all=True # Programmatic force (always works)
|
|
2143
|
-
)
|
|
2144
|
-
```
|
|
2145
|
-
|
|
2146
|
-
---
|
|
2147
|
-
|
|
2148
2171
|
### Issue: Data fetch returns empty or different results
|
|
2149
2172
|
|
|
2150
2173
|
**Symptom:** `get_data()` returns empty list or fewer records than expected.
|
|
@@ -2282,6 +2305,47 @@ ask_values = {"ask1": "value"} # No underscores
|
|
|
2282
2305
|
|
|
2283
2306
|
---
|
|
2284
2307
|
|
|
2308
|
+
### Issue: Lambda has old cached data after I changed report metadata
|
|
2309
|
+
|
|
2310
|
+
**Symptom:** You updated a Quickbase report's fields, filters, or configuration, but your Lambda returns stale data.
|
|
2311
|
+
|
|
2312
|
+
**Cause:** Cache was loaded before your changes, and it hasn't become "stale" enough to auto-refresh yet.
|
|
2313
|
+
|
|
2314
|
+
**Solutions:**
|
|
2315
|
+
|
|
2316
|
+
1. **Quick fix: Use force refresh toggle (development only)**
|
|
2317
|
+
|
|
2318
|
+
In your Lambda handler, temporarily set:
|
|
2319
|
+
```python
|
|
2320
|
+
FORCE_COMPLETE_CACHE_REFRESH_METADATA = True
|
|
2321
|
+
```
|
|
2322
|
+
|
|
2323
|
+
Upload new build, invoke Lambda, check logs for refresh. Then revert flag to `False`.
|
|
2324
|
+
|
|
2325
|
+
2. **For immediate production fix:**
|
|
2326
|
+
|
|
2327
|
+
Manually delete files from S3:
|
|
2328
|
+
```bash
|
|
2329
|
+
aws s3 rm s3://my-quickbase-cache-bucket/prod/cache/report_metadata/ --recursive
|
|
2330
|
+
```
|
|
2331
|
+
|
|
2332
|
+
Next Lambda cold start will re-fetch fresh metadata.
|
|
2333
|
+
|
|
2334
|
+
3. **To prevent in future:**
|
|
2335
|
+
|
|
2336
|
+
Reduce `metadata_stale_hours` threshold:
|
|
2337
|
+
```python
|
|
2338
|
+
ensure_cache_freshness(
|
|
2339
|
+
client=client,
|
|
2340
|
+
cache_manager=cache_mgr,
|
|
2341
|
+
report_configs_all=get_all_reports(),
|
|
2342
|
+
report_configs_to_cache=get_reports_to_cache(),
|
|
2343
|
+
metadata_stale_hours=24 # Check daily instead of 30 days
|
|
2344
|
+
)
|
|
2345
|
+
```
|
|
2346
|
+
|
|
2347
|
+
---
|
|
2348
|
+
|
|
2285
2349
|
### Issue: Performance degradation over time
|
|
2286
2350
|
|
|
2287
2351
|
**Symptom:** First request fast, subsequent requests slow.
|
|
@@ -2453,23 +2517,6 @@ ensure_cache_freshness(
|
|
|
2453
2517
|
)
|
|
2454
2518
|
```
|
|
2455
2519
|
|
|
2456
|
-
#### Environment Variable Force
|
|
2457
|
-
|
|
2458
|
-
Set `FORCE_ALL_CACHE_REFRESH=true` before invoking:
|
|
2459
|
-
|
|
2460
|
-
```bash
|
|
2461
|
-
# In Lambda environment variables or shell
|
|
2462
|
-
export FORCE_ALL_CACHE_REFRESH=true
|
|
2463
|
-
|
|
2464
|
-
# Then call normally (will force refresh automatically)
|
|
2465
|
-
ensure_cache_freshness(
|
|
2466
|
-
client=client,
|
|
2467
|
-
cache_manager=cache_mgr,
|
|
2468
|
-
report_configs_all=get_all_reports(),
|
|
2469
|
-
report_configs_to_cache=get_reports_to_cache()
|
|
2470
|
-
)
|
|
2471
|
-
```
|
|
2472
|
-
|
|
2473
2520
|
### Cache-All-Data Mode
|
|
2474
2521
|
|
|
2475
2522
|
For production, cache data for all reports instead of a subset:
|
|
@@ -2678,6 +2725,95 @@ def scheduled_cache_refresh(event, context):
|
|
|
2678
2725
|
return {"statusCode": 200, "message": "Cache refreshed"}
|
|
2679
2726
|
```
|
|
2680
2727
|
|
|
2728
|
+
### Development/Debug Mode: Forcing Complete Cache Refresh
|
|
2729
|
+
|
|
2730
|
+
When you modify report metadata or configurations in Quickbase, your Lambda may still use stale cached data. Use the force refresh toggles to clear everything and fetch fresh data.
|
|
2731
|
+
|
|
2732
|
+
#### When to Use
|
|
2733
|
+
|
|
2734
|
+
- You changed a report's filters or fields in Quickbase
|
|
2735
|
+
- You added/removed fields from a report
|
|
2736
|
+
- You renamed a report or table
|
|
2737
|
+
- You need to verify fresh data is being fetched
|
|
2738
|
+
|
|
2739
|
+
#### How to Use
|
|
2740
|
+
|
|
2741
|
+
1. Open your Lambda handler code
|
|
2742
|
+
2. Set one of the toggle flags to `True`:
|
|
2743
|
+
|
|
2744
|
+
```python
|
|
2745
|
+
# In lambda_handler, find these lines:
|
|
2746
|
+
FORCE_COMPLETE_CACHE_REFRESH_ALL = False
|
|
2747
|
+
FORCE_COMPLETE_CACHE_REFRESH_METADATA = False
|
|
2748
|
+
FORCE_COMPLETE_CACHE_REFRESH_DATA = False
|
|
2749
|
+
|
|
2750
|
+
# Change to (example: refresh only metadata):
|
|
2751
|
+
FORCE_COMPLETE_CACHE_REFRESH_METADATA = True
|
|
2752
|
+
```
|
|
2753
|
+
|
|
2754
|
+
3. Upload new Lambda build
|
|
2755
|
+
4. Invoke your Lambda (via API or CloudWatch event)
|
|
2756
|
+
5. Check CloudWatch logs for cache refresh messages
|
|
2757
|
+
6. **Revert the flag back to `False`** for normal operation
|
|
2758
|
+
|
|
2759
|
+
#### Flag Options
|
|
2760
|
+
|
|
2761
|
+
| Flag | What Gets Refreshed | Use When |
|
|
2762
|
+
|------|---------------------|----------|
|
|
2763
|
+
| `force_all=True` | Both metadata + data | Complete cache overhaul needed |
|
|
2764
|
+
| `force_metadata=True` | Only metadata | Report configuration changed |
|
|
2765
|
+
| `force_data=True` | Only data | Data needs fresh pull |
|
|
2766
|
+
|
|
2767
|
+
#### What Happens
|
|
2768
|
+
|
|
2769
|
+
When you trigger a force refresh:
|
|
2770
|
+
|
|
2771
|
+
1. ✓ `/tmp` cache directories are deleted
|
|
2772
|
+
2. ✓ Fresh data fetched from Quickbase API
|
|
2773
|
+
3. ✓ Data written to S3
|
|
2774
|
+
4. ✓ `/tmp` re-synced from updated S3
|
|
2775
|
+
|
|
2776
|
+
Your Lambda now has fresh data from Quickbase.
|
|
2777
|
+
|
|
2778
|
+
#### Example
|
|
2779
|
+
|
|
2780
|
+
```python
|
|
2781
|
+
def lambda_handler(event, context):
|
|
2782
|
+
client = get_client()
|
|
2783
|
+
cache_mgr = get_cache_manager()
|
|
2784
|
+
|
|
2785
|
+
# Metadata changed in Quickbase? Force refresh it:
|
|
2786
|
+
FORCE_COMPLETE_CACHE_REFRESH_METADATA = True # ← Toggle this
|
|
2787
|
+
|
|
2788
|
+
if (FORCE_COMPLETE_CACHE_REFRESH_ALL or FORCE_COMPLETE_CACHE_REFRESH_METADATA
|
|
2789
|
+
or FORCE_COMPLETE_CACHE_REFRESH_DATA):
|
|
2790
|
+
from quickbase_extract import complete_cache_refresh
|
|
2791
|
+
complete_cache_refresh(
|
|
2792
|
+
cache_manager=cache_mgr,
|
|
2793
|
+
client=client,
|
|
2794
|
+
report_configs=get_all_reports(),
|
|
2795
|
+
force_metadata=FORCE_COMPLETE_CACHE_REFRESH_METADATA,
|
|
2796
|
+
)
|
|
2797
|
+
|
|
2798
|
+
# Rest of handler...
|
|
2799
|
+
```
|
|
2800
|
+
|
|
2801
|
+
**CloudWatch logs will show:**
|
|
2802
|
+
```
|
|
2803
|
+
WARNING: Starting complete cache refresh for: metadata (clearing /tmp, refreshing from Quickbase, updating S3...)
|
|
2804
|
+
DEBUG: Reset cache sync flag
|
|
2805
|
+
INFO: Fetching fresh data from Quickbase...
|
|
2806
|
+
INFO: Re-syncing /tmp from S3...
|
|
2807
|
+
WARNING: Complete cache refresh finished for metadata: /tmp and S3 now have fresh data from Quickbase
|
|
2808
|
+
```
|
|
2809
|
+
|
|
2810
|
+
#### Important Notes
|
|
2811
|
+
|
|
2812
|
+
- **Don't leave toggles set to `True`** — revert to `False` after testing
|
|
2813
|
+
- **Only for development** — not a production workflow
|
|
2814
|
+
- Logs will show exactly what was refreshed
|
|
2815
|
+
- Safe to use — doesn't affect running processes, only next Lambda invocation
|
|
2816
|
+
|
|
2681
2817
|
## Advanced Usage
|
|
2682
2818
|
|
|
2683
2819
|
### Custom Report Configurations
|
|
@@ -855,7 +855,6 @@ s3://mit-bio-quickbase/my_project/dev/cache/report_metadata/...
|
|
|
855
855
|
| `CACHE_BUCKET` | S3 bucket for Lambda cache | - |
|
|
856
856
|
| `METADATA_STALE_HOURS` | Threshold (hours) for metadata cache staleness | `168` (7 days) |
|
|
857
857
|
| `DATA_STALE_HOURS` | Threshold (hours) for data cache staleness | `24` (1 day) |
|
|
858
|
-
| `FORCE_CACHE_REFRESH` | If set to "true", forces cache refresh on next sync | - |
|
|
859
858
|
|
|
860
859
|
### Custom Cache Location
|
|
861
860
|
|
|
@@ -929,10 +928,30 @@ def lambda_handler(event, context):
|
|
|
929
928
|
- Cold start: Syncs cache from S3
|
|
930
929
|
- Cache freshness: Auto-refreshes if stale
|
|
931
930
|
- Data fetching: Queries Quickbase and caches results
|
|
931
|
+
- Development: Supports forcing complete cache refresh for testing
|
|
932
932
|
"""
|
|
933
933
|
client = get_client()
|
|
934
934
|
cache_mgr = get_cache_manager()
|
|
935
935
|
|
|
936
|
+
# OPTIONAL: Set to True to force cache refresh (for development/debugging only)
|
|
937
|
+
# Only one should be True at a time. force_all overrides the others.
|
|
938
|
+
FORCE_COMPLETE_CACHE_REFRESH_ALL = False
|
|
939
|
+
FORCE_COMPLETE_CACHE_REFRESH_METADATA = False
|
|
940
|
+
FORCE_COMPLETE_CACHE_REFRESH_DATA = False
|
|
941
|
+
|
|
942
|
+
# Force complete cache refresh if needed (dev/debugging only)
|
|
943
|
+
if (FORCE_COMPLETE_CACHE_REFRESH_ALL or FORCE_COMPLETE_CACHE_REFRESH_METADATA
|
|
944
|
+
or FORCE_COMPLETE_CACHE_REFRESH_DATA):
|
|
945
|
+
from quickbase_extract import complete_cache_refresh
|
|
946
|
+
complete_cache_refresh(
|
|
947
|
+
cache_manager=cache_mgr,
|
|
948
|
+
client=client,
|
|
949
|
+
report_configs=get_all_reports(),
|
|
950
|
+
force_all=FORCE_COMPLETE_CACHE_REFRESH_ALL,
|
|
951
|
+
force_metadata=FORCE_COMPLETE_CACHE_REFRESH_METADATA,
|
|
952
|
+
force_data=FORCE_COMPLETE_CACHE_REFRESH_DATA,
|
|
953
|
+
)
|
|
954
|
+
|
|
936
955
|
# Step 1: Sync cache from S3 on cold start (only on first invocation)
|
|
937
956
|
sync_from_s3_once(cache_mgr)
|
|
938
957
|
|
|
@@ -1238,7 +1257,6 @@ Checks metadata and data caches independently. Refreshes only the caches that ar
|
|
|
1238
1257
|
**Environment Variables:**
|
|
1239
1258
|
- `METADATA_STALE_HOURS`: Override default metadata staleness threshold (in hours)
|
|
1240
1259
|
- `DATA_STALE_HOURS`: Override default data staleness threshold (in hours)
|
|
1241
|
-
- `FORCE_ALL_CACHE_REFRESH`: Set to "true" to force refresh regardless of cache state
|
|
1242
1260
|
|
|
1243
1261
|
**Returns:** None
|
|
1244
1262
|
|
|
@@ -1538,6 +1556,48 @@ def lambda_handler(event, context):
|
|
|
1538
1556
|
metadata = load_report_metadata_batch(cache_mgr, config)
|
|
1539
1557
|
```
|
|
1540
1558
|
|
|
1559
|
+
#### `complete_cache_refresh(cache_manager, client, report_configs, force_all=False, force_metadata=False, force_data=False)`
|
|
1560
|
+
|
|
1561
|
+
Completely refresh cache for development/debugging: clear /tmp, fetch fresh from Quickbase, update S3, re-sync to /tmp.
|
|
1562
|
+
|
|
1563
|
+
This is a development utility for forcing a complete cache refresh when report metadata or configurations change. Clears local /tmp cache, fetches fresh data from Quickbase, writes to S3, and re-syncs to /tmp.
|
|
1564
|
+
|
|
1565
|
+
**Parameters:**
|
|
1566
|
+
- `cache_manager` (CacheManager): Cache manager instance
|
|
1567
|
+
- `client`: Quickbase API client for fetching fresh data
|
|
1568
|
+
- `report_configs` (list[ReportConfig]): List of all ReportConfig instances to refresh
|
|
1569
|
+
- `force_all` (bool): If True, refresh both metadata and data. Defaults to False.
|
|
1570
|
+
- `force_metadata` (bool): If True (and `force_all` is False), refresh only metadata. Defaults to False.
|
|
1571
|
+
- `force_data` (bool): If True (and `force_all` is False), refresh only data. Defaults to False.
|
|
1572
|
+
|
|
1573
|
+
**Returns:** None
|
|
1574
|
+
|
|
1575
|
+
**Raises:**
|
|
1576
|
+
- `Exception`: If cache clearing or refresh operations fail
|
|
1577
|
+
|
|
1578
|
+
**Example:**
|
|
1579
|
+
```python
|
|
1580
|
+
from quickbase_extract import complete_cache_refresh
|
|
1581
|
+
|
|
1582
|
+
# Refresh only metadata (after changing report configurations)
|
|
1583
|
+
complete_cache_refresh(
|
|
1584
|
+
cache_manager=cache_mgr,
|
|
1585
|
+
client=qb_client,
|
|
1586
|
+
report_configs=get_all_reports(),
|
|
1587
|
+
force_metadata=True
|
|
1588
|
+
)
|
|
1589
|
+
|
|
1590
|
+
# Refresh all (metadata + data)
|
|
1591
|
+
complete_cache_refresh(
|
|
1592
|
+
cache_manager=cache_mgr,
|
|
1593
|
+
client=qb_client,
|
|
1594
|
+
report_configs=get_all_reports(),
|
|
1595
|
+
force_all=True
|
|
1596
|
+
)
|
|
1597
|
+
```
|
|
1598
|
+
|
|
1599
|
+
**Note:** This function is designed for development/debugging. To use in Lambda, add toggles to your handler (see "Development/Debug Mode" section below).
|
|
1600
|
+
|
|
1541
1601
|
### Query Execution with Retry Logic
|
|
1542
1602
|
|
|
1543
1603
|
#### `handle_query(client, table_id, *, select=None, where=None, sort_by=None, group_by=None, options=None, description="", max_retries=3)`
|
|
@@ -2081,43 +2141,6 @@ fields = info["fields"]
|
|
|
2081
2141
|
|
|
2082
2142
|
---
|
|
2083
2143
|
|
|
2084
|
-
### Issue: "FORCE_CACHE_REFRESH not working"
|
|
2085
|
-
|
|
2086
|
-
**Symptom:** Set `FORCE_CACHE_REFRESH=true` but cache still not refreshing.
|
|
2087
|
-
|
|
2088
|
-
**Cause:** Environment variable case-sensitive or not set correctly.
|
|
2089
|
-
|
|
2090
|
-
**Solution:**
|
|
2091
|
-
|
|
2092
|
-
1. **Verify env var is set (case-sensitive):**
|
|
2093
|
-
```bash
|
|
2094
|
-
# Must be exactly this (uppercase)
|
|
2095
|
-
export FORCE_ALL_CACHE_REFRESH=true
|
|
2096
|
-
|
|
2097
|
-
# Not these (wrong):
|
|
2098
|
-
export force_cache_refresh=true
|
|
2099
|
-
export Force_Cache_Refresh=true
|
|
2100
|
-
```
|
|
2101
|
-
|
|
2102
|
-
2. **Verify it's being read:**
|
|
2103
|
-
```python
|
|
2104
|
-
import os
|
|
2105
|
-
print(os.environ.get("FORCE_ALL_CACHE_REFRESH")) # Should print "true"
|
|
2106
|
-
```
|
|
2107
|
-
|
|
2108
|
-
3. **Use programmatic force instead:**
|
|
2109
|
-
```python
|
|
2110
|
-
ensure_cache_freshness(
|
|
2111
|
-
client=client,
|
|
2112
|
-
cache_manager=cache_mgr,
|
|
2113
|
-
report_configs_all=get_all_reports(),
|
|
2114
|
-
report_configs_to_cache=get_reports_to_cache(),
|
|
2115
|
-
force_all=True # Programmatic force (always works)
|
|
2116
|
-
)
|
|
2117
|
-
```
|
|
2118
|
-
|
|
2119
|
-
---
|
|
2120
|
-
|
|
2121
2144
|
### Issue: Data fetch returns empty or different results
|
|
2122
2145
|
|
|
2123
2146
|
**Symptom:** `get_data()` returns empty list or fewer records than expected.
|
|
@@ -2255,6 +2278,47 @@ ask_values = {"ask1": "value"} # No underscores
|
|
|
2255
2278
|
|
|
2256
2279
|
---
|
|
2257
2280
|
|
|
2281
|
+
### Issue: Lambda has old cached data after I changed report metadata
|
|
2282
|
+
|
|
2283
|
+
**Symptom:** You updated a Quickbase report's fields, filters, or configuration, but your Lambda returns stale data.
|
|
2284
|
+
|
|
2285
|
+
**Cause:** Cache was loaded before your changes, and it hasn't become "stale" enough to auto-refresh yet.
|
|
2286
|
+
|
|
2287
|
+
**Solutions:**
|
|
2288
|
+
|
|
2289
|
+
1. **Quick fix: Use force refresh toggle (development only)**
|
|
2290
|
+
|
|
2291
|
+
In your Lambda handler, temporarily set:
|
|
2292
|
+
```python
|
|
2293
|
+
FORCE_COMPLETE_CACHE_REFRESH_METADATA = True
|
|
2294
|
+
```
|
|
2295
|
+
|
|
2296
|
+
Upload new build, invoke Lambda, check logs for refresh. Then revert flag to `False`.
|
|
2297
|
+
|
|
2298
|
+
2. **For immediate production fix:**
|
|
2299
|
+
|
|
2300
|
+
Manually delete files from S3:
|
|
2301
|
+
```bash
|
|
2302
|
+
aws s3 rm s3://my-quickbase-cache-bucket/prod/cache/report_metadata/ --recursive
|
|
2303
|
+
```
|
|
2304
|
+
|
|
2305
|
+
Next Lambda cold start will re-fetch fresh metadata.
|
|
2306
|
+
|
|
2307
|
+
3. **To prevent in future:**
|
|
2308
|
+
|
|
2309
|
+
Reduce `metadata_stale_hours` threshold:
|
|
2310
|
+
```python
|
|
2311
|
+
ensure_cache_freshness(
|
|
2312
|
+
client=client,
|
|
2313
|
+
cache_manager=cache_mgr,
|
|
2314
|
+
report_configs_all=get_all_reports(),
|
|
2315
|
+
report_configs_to_cache=get_reports_to_cache(),
|
|
2316
|
+
metadata_stale_hours=24 # Check daily instead of 30 days
|
|
2317
|
+
)
|
|
2318
|
+
```
|
|
2319
|
+
|
|
2320
|
+
---
|
|
2321
|
+
|
|
2258
2322
|
### Issue: Performance degradation over time
|
|
2259
2323
|
|
|
2260
2324
|
**Symptom:** First request fast, subsequent requests slow.
|
|
@@ -2426,23 +2490,6 @@ ensure_cache_freshness(
|
|
|
2426
2490
|
)
|
|
2427
2491
|
```
|
|
2428
2492
|
|
|
2429
|
-
#### Environment Variable Force
|
|
2430
|
-
|
|
2431
|
-
Set `FORCE_ALL_CACHE_REFRESH=true` before invoking:
|
|
2432
|
-
|
|
2433
|
-
```bash
|
|
2434
|
-
# In Lambda environment variables or shell
|
|
2435
|
-
export FORCE_ALL_CACHE_REFRESH=true
|
|
2436
|
-
|
|
2437
|
-
# Then call normally (will force refresh automatically)
|
|
2438
|
-
ensure_cache_freshness(
|
|
2439
|
-
client=client,
|
|
2440
|
-
cache_manager=cache_mgr,
|
|
2441
|
-
report_configs_all=get_all_reports(),
|
|
2442
|
-
report_configs_to_cache=get_reports_to_cache()
|
|
2443
|
-
)
|
|
2444
|
-
```
|
|
2445
|
-
|
|
2446
2493
|
### Cache-All-Data Mode
|
|
2447
2494
|
|
|
2448
2495
|
For production, cache data for all reports instead of a subset:
|
|
@@ -2651,6 +2698,95 @@ def scheduled_cache_refresh(event, context):
|
|
|
2651
2698
|
return {"statusCode": 200, "message": "Cache refreshed"}
|
|
2652
2699
|
```
|
|
2653
2700
|
|
|
2701
|
+
### Development/Debug Mode: Forcing Complete Cache Refresh
|
|
2702
|
+
|
|
2703
|
+
When you modify report metadata or configurations in Quickbase, your Lambda may still use stale cached data. Use the force refresh toggles to clear everything and fetch fresh data.
|
|
2704
|
+
|
|
2705
|
+
#### When to Use
|
|
2706
|
+
|
|
2707
|
+
- You changed a report's filters or fields in Quickbase
|
|
2708
|
+
- You added/removed fields from a report
|
|
2709
|
+
- You renamed a report or table
|
|
2710
|
+
- You need to verify fresh data is being fetched
|
|
2711
|
+
|
|
2712
|
+
#### How to Use
|
|
2713
|
+
|
|
2714
|
+
1. Open your Lambda handler code
|
|
2715
|
+
2. Set one of the toggle flags to `True`:
|
|
2716
|
+
|
|
2717
|
+
```python
|
|
2718
|
+
# In lambda_handler, find these lines:
|
|
2719
|
+
FORCE_COMPLETE_CACHE_REFRESH_ALL = False
|
|
2720
|
+
FORCE_COMPLETE_CACHE_REFRESH_METADATA = False
|
|
2721
|
+
FORCE_COMPLETE_CACHE_REFRESH_DATA = False
|
|
2722
|
+
|
|
2723
|
+
# Change to (example: refresh only metadata):
|
|
2724
|
+
FORCE_COMPLETE_CACHE_REFRESH_METADATA = True
|
|
2725
|
+
```
|
|
2726
|
+
|
|
2727
|
+
3. Upload new Lambda build
|
|
2728
|
+
4. Invoke your Lambda (via API or CloudWatch event)
|
|
2729
|
+
5. Check CloudWatch logs for cache refresh messages
|
|
2730
|
+
6. **Revert the flag back to `False`** for normal operation
|
|
2731
|
+
|
|
2732
|
+
#### Flag Options
|
|
2733
|
+
|
|
2734
|
+
| Flag | What Gets Refreshed | Use When |
|
|
2735
|
+
|------|---------------------|----------|
|
|
2736
|
+
| `force_all=True` | Both metadata + data | Complete cache overhaul needed |
|
|
2737
|
+
| `force_metadata=True` | Only metadata | Report configuration changed |
|
|
2738
|
+
| `force_data=True` | Only data | Data needs fresh pull |
|
|
2739
|
+
|
|
2740
|
+
#### What Happens
|
|
2741
|
+
|
|
2742
|
+
When you trigger a force refresh:
|
|
2743
|
+
|
|
2744
|
+
1. ✓ `/tmp` cache directories are deleted
|
|
2745
|
+
2. ✓ Fresh data fetched from Quickbase API
|
|
2746
|
+
3. ✓ Data written to S3
|
|
2747
|
+
4. ✓ `/tmp` re-synced from updated S3
|
|
2748
|
+
|
|
2749
|
+
Your Lambda now has fresh data from Quickbase.
|
|
2750
|
+
|
|
2751
|
+
#### Example
|
|
2752
|
+
|
|
2753
|
+
```python
|
|
2754
|
+
def lambda_handler(event, context):
|
|
2755
|
+
client = get_client()
|
|
2756
|
+
cache_mgr = get_cache_manager()
|
|
2757
|
+
|
|
2758
|
+
# Metadata changed in Quickbase? Force refresh it:
|
|
2759
|
+
FORCE_COMPLETE_CACHE_REFRESH_METADATA = True # ← Toggle this
|
|
2760
|
+
|
|
2761
|
+
if (FORCE_COMPLETE_CACHE_REFRESH_ALL or FORCE_COMPLETE_CACHE_REFRESH_METADATA
|
|
2762
|
+
or FORCE_COMPLETE_CACHE_REFRESH_DATA):
|
|
2763
|
+
from quickbase_extract import complete_cache_refresh
|
|
2764
|
+
complete_cache_refresh(
|
|
2765
|
+
cache_manager=cache_mgr,
|
|
2766
|
+
client=client,
|
|
2767
|
+
report_configs=get_all_reports(),
|
|
2768
|
+
force_metadata=FORCE_COMPLETE_CACHE_REFRESH_METADATA,
|
|
2769
|
+
)
|
|
2770
|
+
|
|
2771
|
+
# Rest of handler...
|
|
2772
|
+
```
|
|
2773
|
+
|
|
2774
|
+
**CloudWatch logs will show:**
|
|
2775
|
+
```
|
|
2776
|
+
WARNING: Starting complete cache refresh for: metadata (clearing /tmp, refreshing from Quickbase, updating S3...)
|
|
2777
|
+
DEBUG: Reset cache sync flag
|
|
2778
|
+
INFO: Fetching fresh data from Quickbase...
|
|
2779
|
+
INFO: Re-syncing /tmp from S3...
|
|
2780
|
+
WARNING: Complete cache refresh finished for metadata: /tmp and S3 now have fresh data from Quickbase
|
|
2781
|
+
```
|
|
2782
|
+
|
|
2783
|
+
#### Important Notes
|
|
2784
|
+
|
|
2785
|
+
- **Don't leave toggles set to `True`** — revert to `False` after testing
|
|
2786
|
+
- **Only for development** — not a production workflow
|
|
2787
|
+
- Logs will show exactly what was refreshed
|
|
2788
|
+
- Safe to use — doesn't affect running processes, only next Lambda invocation
|
|
2789
|
+
|
|
2654
2790
|
## Advanced Usage
|
|
2655
2791
|
|
|
2656
2792
|
### Custom Report Configurations
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "quickbase-extract"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "Extract and cache Quickbase report data with built-in error handling and S3 support"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|