perf(extract): parallel page fetching in tenants, drop EXTRACT_WORKERS env var

- playtomic_tenants.py: batch_size = len(proxy_urls) pages fired in parallel per
  batch; each page gets its own session + proxy; sorted(results) ensures
  deterministic done-detection; falls back to serial + THROTTLE_SECONDS when no
  proxies. Expected speedup: ~2.5 min → ~15 s with 10 proxies.
- .env.dev.sops, .env.prod.sops: remove EXTRACT_WORKERS (now derived from
  PROXY_URLS length)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Deeman
2026-02-24 22:30:28 +01:00
parent 6116445b56
commit 9f010d8c0c
3 changed files with 192 additions and 140 deletions

View File

@@ -1,77 +1,76 @@
#ENC[AES256_GCM,data:OODjUg==,iv:E1PqA4jzCrltGb9T8tiB2wrkLmzefekOVJt3jXze6bI=,tag:t+nmaZ+gsR0Qr3XeJ/szMg==,type:comment]
APP_NAME=ENC[AES256_GCM,data:MIW1LUcXGSRAXQo=,iv:WlHAjnFaoo5HgsyqGnvbiuMfvZIYXeA+ssw43fsP3TM=,tag:BOGuyhHj5+T1Tg7TBbCPHQ==,type:str]
SECRET_KEY=ENC[AES256_GCM,data:F43Bn1FzhYyzdGINTQA90Uw2aZWJ7REhVnM5Tc6KFS8=,iv:ZAbWVSCrVDKqVzPkNfAvH6p8iRISZSTD4U68JVZwL7Q=,tag:B5tmroCp3EJ+QDnGXgbXOg==,type:str]
BASE_URL=ENC[AES256_GCM,data:wmh0BoYwd3GutNhk7uQZKO4MAXin,iv:uZ4FivDic5KL7fQvrH1rhN4bTmXWqnHfzMJq7/4o+5w=,tag:NFfkEGkS1vxjODo/zB5Mcg==,type:str]
DEBUG=ENC[AES256_GCM,data:aqfTbw==,iv:g7jWtA4OD+b7QW4Sor7dX/6pJxif7d2SiU/An21QSfY=,tag:sjSyQQNtk0rLaOhYzNbAKw==,type:str]
#ENC[AES256_GCM,data:dSj2wIiLuhNq9FvDEhTL3F6LBJ4ITNsaKYO1YRmLZLDS3+C0jk7Hx5kPjcor4T9kst5tOE1KMH7HKn+0CHeWf+pdidAWikd1xA==,iv:hbnREdnOSgivoTI9/GwUOpRg1yROIgjbTpiR1R9u3AI=,tag:am/IFpc8a8Du0Wx8X7u9nA==,type:comment]
ADMIN_EMAILS=ENC[AES256_GCM,data:yS0kOYrM5VRhAAkxqg==,iv:eCqHA4kcgwt9T03Umq8MYiLYeB+Zh3pL9R7adcSZkYw=,tag:k3O0EbevHeWgG1JQAh30hw==,type:str]
#ENC[AES256_GCM,data:FDydGDKV+yuB,iv:3Q2JHDLqOWS/R+91Kx+5l7IST9DRngBd7Nd2Oau0kFw=,tag:JmavycCv5EeW7nDCum9SsA==,type:comment]
DATABASE_PATH=ENC[AES256_GCM,data:2INhi9u4WHoC6eA=,iv:JvkmUtrd5oxw0ZGQJAhI4kj1MtPqxRi5keGIzgCHcPQ=,tag:T7Yb1QKkVR3U7Ww5puKinA==,type:str]
#ENC[AES256_GCM,data:c3ikDZY=,iv:ssaKWl8+ddTa48pst3cz2n5ywMqMdrUN69jlLGRbgJU=,tag:7Dk53YiaBzYCyrrddUHb1A==,type:comment]
MAGIC_LINK_EXPIRY_MINUTES=ENC[AES256_GCM,data:gCw=,iv:u+tNE3Jc0GD1JJB7gX4MFelHb0JhqOiFAjP5cvsS1eU=,tag:hQJPei0T/Hz8eUnUmGxnyQ==,type:str]
SESSION_LIFETIME_DAYS=ENC[AES256_GCM,data:NT0=,iv:wzqXr3Stux9WrJBF89iYtmZMuoog2jr5ScTd+W3T9E4=,tag:Ei/FtIMAmBChc1Q6GS01SA==,type:str]
#ENC[AES256_GCM,data:0gHTU0jfkx3K/aeVQ4ab,iv:MhpRgozzMhtlDw05jDdPvNB9linCCep8WWPXFCxESI0=,tag:yxQncJ6uBHPGM2PsgsqA2w==,type:comment]
#ENC[AES256_GCM,data:N1R78wzjduwR6vj2/2io04RHvDz4bdMZQah2eG6iuQfe76dk4yVA2is6vIAO0wGHQbKOFj2XCFnex9h6LK7yfVB2TNNxndTLDOemlg==,iv:ifFHqlb2oY4flnWX3sDYKEFP3cufi5pfuF1H0zjZGRQ=,tag:ZJC6zkPE5/29GCpRK6G7QA==,type:comment]
#ENC[AES256_GCM,data:9JNa0g==,iv:KnGl3/4KQWkVnFXn9iKU5z5Ys6KXWOnSEoE/Jjks2pw=,tag:ZD3nrOQmhUjPkZiwtV330g==,type:comment]
APP_NAME=ENC[AES256_GCM,data:Vic/MJYoxZo8JAI=,iv:n1SEGQaGeZtYMtLmDRFiljDBbNKFvCzZPNtaFBNauYY=,tag:Smsd20Ba56QZKVFpRmhRPQ==,type:str]
SECRET_KEY=ENC[AES256_GCM,data:a3Bhj3gSQaE3llRWBYzpjoFDhhhSsNee67jXJs7+qn4=,iv:yvrx78X5Ut4DBSlmBnIn09ESVc/tuDiwiV4njmjcvko=,tag:cbFUTAEpX+isQD9FCVllsw==,type:str]
BASE_URL=ENC[AES256_GCM,data:LcbPDZf9Pwcuv7RxN9xhNfa9Tufi,iv:cOdjW9nNe+BuDXh+dL4b5LFQL2mKBiKV0FaEsDGMAQc=,tag:3uAn3AIwsztIfGpkQLD5Fg==,type:str]
DEBUG=ENC[AES256_GCM,data:qrEGkA==,iv:bCyEDWiEzolHo4vabiyYTsqM0eUaBmNbXYYu4wCsaeE=,tag:80gnDNbdZHRWVEYtuA1M2Q==,type:str]
#ENC[AES256_GCM,data:YmlGAWpXxRCqam3oTWtGxHDXC+svEXI4HyUxrm/8OcKTuJsYPcL1WcnYqrP5Mf5lU5qPezEXUrrgZy8vjVW6qAbb0IA2PMM4Kg==,iv:dx6Dn99dJgjwyvUp8NAygXjRQ50yKYFeC73Oqt9WvmY=,tag:6JLF2ixSAv39VkKt6+cecQ==,type:comment]
ADMIN_EMAILS=ENC[AES256_GCM,data:hlG8b32WlD4ems3VKQ==,iv:wWO08dmX4oLhHulXg4HUG0PjRnFiX19RUTkTvjqIw5I=,tag:KMjXsBt7aE/KqlCfV+fdMg==,type:str]
#ENC[AES256_GCM,data:b2wQxnL8Q2Bp,iv:q8ep3yUPzCumpZpljoVL2jbcPdsI5c2piiZ0x5k10Mw=,tag:IbjkT0Mjgu9n+6FGiPVihg==,type:comment]
DATABASE_PATH=ENC[AES256_GCM,data:pEpMUrL7ZHAzMT4=,iv:eDGudDVsW5vF0sENri7gQrFlCEdoWYP6hT5ZeXXs3Zg=,tag:Gl91C6uRdCiJ7Jo1Z/MQsg==,type:str]
#ENC[AES256_GCM,data:xVzlko4=,iv:glHTshoRIkIaJNpn4onyAxPOtXTsNh/JohXJyyu4Ars=,tag:fQ/53HdxYXs2JTMx6O8rrA==,type:comment]
MAGIC_LINK_EXPIRY_MINUTES=ENC[AES256_GCM,data:Ua4=,iv:ou1kEn+fa42lZDsXaPvpodJcvAF+EZC9UIGNK/tBV/U=,tag:+ed8Bm/8pdIksH7O2X8WwQ==,type:str]
SESSION_LIFETIME_DAYS=ENC[AES256_GCM,data:/gk=,iv:kKWy+FaoLp8kAWpZzpoUHX8nVFRaA4yuTTVzN2TSYTs=,tag:QypZTVmTo4lXd7PKTWrBdA==,type:str]
#ENC[AES256_GCM,data:8HLEkeUESRt3bOxIQsma,iv:kzt8+SFNJw2r3LqwwQPzs9bCdacYSfHWPzIvTxARI4k=,tag:n+F13eILUiJCZ3NtQdo26g==,type:comment]
#ENC[AES256_GCM,data:cGkjKPIfdOPWoZFEXTAgw5lsu0LIcNhu1y3ab47kKbVEZMiCk+0KrEUNJcqbQ+ProBQ6F6N38PUhUl0lhKKjMqjepMZUUrUTqFp0Tw==,iv:WyFISLnRnSSOkra/p7bOs5BQWx+qFaaeeZM50EdrIgA=,tag:UM0EiRGy+RFXfdJqRuv3Jw==,type:comment]
#
#ENC[AES256_GCM,data:tuw7/hEPqtY59Y+L3Nq/Y6op26+U05GzZjQpGpwskwXJk5fauks66lPr+P9vlgEJXPOzuF1ZmB+M9td780mXavW49PKVh5NnjP/GbQ8t0Gc=,iv:wj6MCF/ujeaIoYC+pcgeW+slt1CBYPK5Lj4+LyHfehg=,tag:9EJJ46Exxd2On2SdCba+vQ==,type:comment]
#ENC[AES256_GCM,data:KApVqBUmJYwUpHp6BPBkzzVR+BPe8h/u79lODjPLvQoCT9XIfJ3ulZngRUUIDCJr6+yM4y98qxQJf7bhs4z7CK6oB1L/,iv:FAuFeIOD/Rx81L97cAqYIPZ3bhyrqOReQ5xeOjyN/m8=,tag:Z69JIWO4e/Q8+BQ5ThslVg==,type:comment]
#ENC[AES256_GCM,data:80vv1OoLoWwS+J9cbZ1Nt+UeF6Fc4D8LUHLX5BiEmBQAXh8ti3EZZnwi2QZb0wN+Ma1zwsM=,iv:6xnMzedX62XPU3GGpoTie8RZDFlzvrpFMc4u+fCbKYw=,tag:V7HtIqw1+ltW4dbvqobjQA==,type:comment]
#ENC[AES256_GCM,data:irTPd03a7pDOi2WOsL43GB3c/luAhlm0u6b3Wj/oLKnlzmmUV++aoyDum32wGLI4qH9Sy5XJS44=,iv:HH3uPdh0ZBdvX2bhH5w22TCsn67HaJa+/f5bk8NJNvA=,tag:f4xcS4URJS1EAipjcpFn2A==,type:comment]
#ENC[AES256_GCM,data:uW8E3Yhcepw3FJ3En5N8CLpN70a1ovXZJyS/gSqaWsMtScbTEqlMZ39R0S8hiS3j1y7ST7GaNXburXx0lv8=,iv:Xk8GhHPk7zVnMi4PbazefyxumHSv/XwpO/lk2SCxYEc=,tag:r5IpNFQ0wxQ05+UfOaenig==,type:comment]
#ENC[AES256_GCM,data:Ep/iNZ9JUQTFhk63ukNzs4YltDYEZ1b4jvi3yBpT2yfnSuVvrz1xSc+oU5WbHI8SeGbpaTgn5eA=,iv:vry5r45x5xNcIr1oyCbVAkFxFq2vpvvOEzqlvWI/bQc=,tag:MjTSas4nqwHg7J2ZfxlkfQ==,type:comment]
#ENC[AES256_GCM,data:OwkE2btYFBq2akgxnlHA3lVUJ4eXI4YVjIxlbK4lbrn6cd9U6xz7DhrDuFbOxMo1VtbyxBQ6dCBM5TODPHMFRBCIyuuXQi17,iv:emVmqGfwrpkF5HoQ0OD0UhiN076RezDEgsmBm2e5FZg=,tag:Hj+KHO9yKGqv2W5XkkHCZg==,type:comment]
#ENC[AES256_GCM,data:icBc0Zv+oedobh8DOTwV2Fc+N0C9CqjZvLciC1dmEIygr/P5oOBLH9Bnhf7XW3X+fiLUtLPQPUIh9CjX+wVeX+MpUZj8ksS0meoz1O2kSBs=,iv:oWreqF6QxaFZn2r35uqY7yy/nItwy3k3VuXAcLyqMbI=,tag:ezQO+m6qkQSEwe17vYtYcw==,type:comment]
#ENC[AES256_GCM,data:BmlWl0f3aiOrEVglJisqHb507/ipmyRCUvkygs2jBfh2gw3BJgrCAAqoK+DekvIls2myRn7RynqWTMZKGXtJMHu5SEA8,iv:QjPoSzyNl6CBYmJAd2OfFEEoXO3jz0LL2VNegP0mY8Q=,tag:miTvj9PK1a00BKaAjUTICw==,type:comment]
#ENC[AES256_GCM,data:kzSYQCopgU9wXpw61WGfYpRtOjV3iEVvZ09RP4OqVl+Rqnd2wCKREKKrB7F15bp4BB3OzMo=,iv:TFFpROfYKaUlWQm3ISYkyYdZCarSJbqHItLMUplYiXc=,tag:Xbk3ii3DYE4yPe8cJOt+Tw==,type:comment]
#ENC[AES256_GCM,data:qbh0Mnu6wEbDaBideJQCZa74G/DqSWuoiy22zCGoKqKZ2YVQEf0QxRCO/DgOD8rdp1Neqp8u4oE=,iv:dKV76b8sT1ghlyEadeAqTjtNTXrBp9n5ZbGMGi2/GyU=,tag:1HsI5iDekTqxeYmcEpL3HA==,type:comment]
#ENC[AES256_GCM,data:kTLnLnwPVVDFKYncBbFjGmnbxmNfpPXSpKyZu5ZQx6PeVs5s6hpDa55zRXxAetyBAHsmV99ZV2q1NTDXF6Q=,iv:m/ulRFQcGl15vi2ohMwVeYBmcRtp274ROiKXPsyJkfQ=,tag:T0E5p4d/inHyuupbg7bZHQ==,type:comment]
#ENC[AES256_GCM,data:aziyEFGCGxbc+q2ma2QN4MvdhQ6bnYuZA7Cgqr6p3zGjPG3oybTWwILejJqD2lHmULXh0UN0qco=,iv:XZwwEUOAEXIUyXiiHFS/bdL91bWKIhZ5IzcXWXAR63Y=,tag:JLsDM4s2yh4aBFQtxWLhDA==,type:comment]
#ENC[AES256_GCM,data:JroBWIbSs5a7+lg/AtBNPxgbtxaztjmVzI1JXuhBmfWD45Qp+w8ePZg9PA1FYzPtEATPHso6m3tZdMTrPtv4Jj6ig/+KHOLn,iv:CbJp6MHOU4yk9OdynQTPwVgZj9Djw9IC9TE90go5RDk=,tag:NTVDg0mFeZsxfVeIFwFhPw==,type:comment]
#
#ENC[AES256_GCM,data:1rm7G2bjcRWiQBcHI3v6/iVxnASJKchxrEot8YznFxoaGcEQNyQQXapZUFRR02pT9FT+vy6mCWxDyqRdyrtdlGjIL+N5R0ukNcI=,iv:dAFaoyjPikp3gOCIph6UWVrAR3ascxMKr+weOCAqO0Y=,tag:a8aDQifsAp/6+uemGMwryg==,type:comment]
#ENC[AES256_GCM,data:JDxXJ3IJVaBF+MOWe0WXBOPnee48RyjNDtflwVM2FFbLSp1h2uYf6+aRjC4w6pb/R1pl9+AzjjlQaTukjQVwXfbBVKH8SAbhOdU=,iv:K9kvgAbltLIcBo4vZ8NUiaL/Ik+x5Arl9Pj5sh3SIHo=,tag:IjneoyVD+dxd6N2PVV43ww==,type:comment]
RESEND_API_KEY=
EMAIL_FROM=ENC[AES256_GCM,data:aKRFxdRPnDMs5ch7uYx2l2D5kwg=,iv:cxmNdrdXZnRjI0oDXUrz028mI7KnSUXK/pUz71NkUUA=,tag:UjKqpg6oq1t2WIdaXGHzaA==,type:str]
LEADS_EMAIL=ENC[AES256_GCM,data:BJ9r1b4E2Ck2b162f6K2P6z2rXs=,iv:NmrlbVJU7pfBf7pXc4No+69AyvqgF0j7vZEkSvYV6SE=,tag:fI3oyLbePaqi9TqkiJXZtA==,type:str]
EMAIL_FROM=ENC[AES256_GCM,data:QX6duq5wx3z98o39nRXTrPpNXwI=,iv:ikpykHOeHRay+k3B4MvHn2SOuHNGOIuvjetOt+cjTrQ=,tag:8ryM56ogWySp9RAv0/ABTg==,type:str]
LEADS_EMAIL=ENC[AES256_GCM,data:aVFgeh0Yx7W/88noeURvf8rirv8=,iv:5KjsCMAsu1Ywz4BI2JjB1KmQ6QM94U1zlNGJ3BKl7Uo=,tag:voi0kjdhz0SsOQHqtMID4Q==,type:str]
RESEND_WEBHOOK_SECRET=
#ENC[AES256_GCM,data:6T9lVhn+1mcyCxBYy/dsPaGp0zy8+XQRhRCFKxlos4QOIiLBjrYuI11v2oSO80Nn6AfGNms40ewi4RpHtt7Afawb3A==,iv:f9gfD7cM3WJGdvtFQ3Svi8Cui2yadmMXfuF6IAIn/LI=,tag:3jt5lFeI0P827LqQWUGzOA==,type:comment]
#ENC[AES256_GCM,data:ja0Rgj3IVihRU618EIroO3bJg9sWFOd3Ua88HLP9yrzEZ7Ty8Havd+2vroD/TGeidqjiFmpMlXH2R3v1jLrviRbkWqBlbBO4se4G,iv:IfuAx8HcJByEcLaqegqZZZVNfO9H8LnuPzIcXHYRBDY=,tag:FumQcnMmcKHI81FjYrT8Mw==,type:comment]
#ENC[AES256_GCM,data:eHDEBuHGW7rKMPW1NM9b47rBS9BMmtmrwICbijYIVdogMvqJCMEk8zfT/lc/bnXFiamFYfJhhHDNEEOBg69ZdZ7M+mWPCRps6cXP6A==,iv:7SDIHytbnp/v6zXG0j4PbkIIzjeDVqp4BKthmTIqF1M=,tag:+fPDhe9NIe2Qmqp91KuRjw==,type:comment]
#ENC[AES256_GCM,data:VrBNRBK97VxVTcwPZItM14tr5IbWQ2jGTLh1Hca4TPHGWPo75fxUa8MFWSCUcwXIKjMm,iv:FRa+BpQFtyx5BuNt609duHng+QgMbQavvOzDpPb0Ta8=,tag:+OiUXm7Vh+xhdfQ33KEhSQ==,type:comment]
#ENC[AES256_GCM,data:1HqXvAspvNIUNpCxJwge3mEsyO0Y/EWvD3vbLxkgGqIex0hABcupX/Nzk15u8iOY5JWvvEuAO414MNt6mFvnWBDpEw==,iv:N7gCzTNJAR/ljx5gGsX+ieZctya8vQbCIb3hw49OhXg=,tag:PJKNyzhrit5VgIXl+cNlbQ==,type:comment]
#ENC[AES256_GCM,data:do6DZ/1Osc5y4xseG8Q8bDX84JBHLzvmVbHiqxP7ChlicmzYBkZ85g43BuM7V0KInFTFgvaC8xmFic+2d37Holuf1ywdAjbLkRhg,iv:qrNmhPbmFDr2ynIF5EdOLZl3FI5f68WDrxuHMkAzuuU=,tag:761gYOlEdNM+e1//1MbCHg==,type:comment]
#ENC[AES256_GCM,data:dseLIQiUEU20xJqoq2dkFho9SnKyoyQ8pStjvfxwnj8v18/ua0TH/PDx/qwIp9z5kEIvbsz5ycJesFfKPhLA5juGcdCbi5zBmZRWYg==,iv:7JUmRnohJt0H5yoJXVD3IauuJkpPHDPyY02OWHWb9Nw=,tag:KcM6JGT01Aa1kTx+U30UKQ==,type:comment]
#ENC[AES256_GCM,data:GgXo4zkhJsxXEk8F5a/+wdbvBUGN00MUAutZYLDEqqN4T1rZu92fioOLx7MEoC0b8i61,iv:f1hUBoZpmnzXNcikf/anVNdRSHNwVmmjdIcba3eiRI4=,tag:uWpF40uuiXyWqKrYGyLVng==,type:comment]
PADDLE_API_KEY=
PADDLE_CLIENT_TOKEN=
PADDLE_WEBHOOK_SECRET=
PADDLE_NOTIFICATION_SETTING_ID=
PADDLE_ENVIRONMENT=ENC[AES256_GCM,data:Xm4mm3DBjg==,iv:6k4ZSP7GQF4LwVG0OAMBdInAfaf3hhJLjmIztNfdCWg=,tag:/LJeoFbovsvzP7GBEiLsTA==,type:str]
#ENC[AES256_GCM,data:1c0sgo2l+OssNz8Rgm8/DI5ormrHXNHKDTKx6bWmv/2CchefqxsRq1uS7uR5c86eTxfp023LGhy947i7,iv:PAEdaE/pgfy3jxuod1PJ6VcyIYOKmlKkPmudSs5xbxw=,tag:KYnQmbim+fWsnW6nlEnhGA==,type:comment]
UMAMI_API_URL=ENC[AES256_GCM,data:yj4OYkvZIDrgjgkdM3a8xyzvoGJOk75wUhAgNQ==,iv:JmQMdU9XZ5ABfvk0w3XP/WkdcR1KrgXTPVI39+drhO8=,tag:jW1MUL5Nv+z8KP9FjmYFcg==,type:str]
PADDLE_ENVIRONMENT=ENC[AES256_GCM,data:KIGNxEaodA==,iv:SRebaYRpVJR0LpfalBZJLTE8qBGwWZB/Fx3IokQF99Q=,tag:lcC56e4FjVkCiyaq41vxcQ==,type:str]
#ENC[AES256_GCM,data:2Hs7ds2ppeRqKB7EiAAbWqlainKdZ+eTYZSvPloirT4Hlsuf+zTwtJTA6RzHNCuK4em//jhOx8R2k80I,iv:1N6CNPqYWp3z8lm5e2Vp6OlpgHdMOiD7dsEYp23nMtA=,tag:ulWP/BFFoLljLMVCrsgizw==,type:comment]
UMAMI_API_URL=ENC[AES256_GCM,data:oX/m95YB+S2ziUKoxDhsDzMhGZfxppw+w603tQ==,iv:GAj7ccF6seiCfLAh2XIjUi13RpgNA3GONMtINcG+KMw=,tag:mUfRlvaEWrw2QWFydtnbNA==,type:str]
UMAMI_API_TOKEN=
#ENC[AES256_GCM,data:5nypMO9DFup4c3p0xXM=,iv:GdbOATtVOmFZKvDfv4gdNDDdq4WmB+/yk/D/xgC7Uos=,tag:TWfgxyuzlzvzxJRMF0L0cA==,type:comment]
RATE_LIMIT_REQUESTS=ENC[AES256_GCM,data:o/R0,iv:TGPynY3rpH5fL8zQvI9EAWg/LFv7earnaCbGhkkN2FE=,tag:lpnRZGaONv1TZdwJg17AIg==,type:str]
RATE_LIMIT_WINDOW=ENC[AES256_GCM,data:2dU=,iv:6wSl6GAWAVxfVC/LB0uqhB+8gtHhkrFybASXdQseuVk=,tag:gVjomO7E837h/plD/8948Q==,type:str]
#ENC[AES256_GCM,data:7CoH3Rv284IHofVG9bruk5NYF9S4oeGqupZFQ38OpfCde1p9ks7WGicFmfrMQDNTLG1YoR3TD/u/XQ+19SoP+XTcSlhoYwo2mx19ETWnww4=,iv:BvgKjGm1YB97I8EQG74uaoDk1QraWxTVtZoiNGkdx6U=,tag:vbS882eevc0rzOA9pGtzng==,type:comment]
#ENC[AES256_GCM,data:HTG/nKNl9NMicZVt5nU=,iv:MfRqX6tzdl6SC61xjRxTrVRpTWGmmqslL/Vdy88Jtyo=,tag:NhOgm3+qJelmQaAAnITFKA==,type:comment]
RATE_LIMIT_REQUESTS=ENC[AES256_GCM,data:hy3B,iv:kouDI24Gac/S7aQMXRcl+emwE6/WU+F9egNhQ+MayrA=,tag:iZXV92kqnS0MppvW6Km5oQ==,type:str]
RATE_LIMIT_WINDOW=ENC[AES256_GCM,data:vE8=,iv:lS6cQX3VzHeVrlYHQTXYGgib1rYI9G4XoW/f5YSjVWs=,tag:3Bn8PIktDxD7HvUTHw6mnw==,type:str]
#ENC[AES256_GCM,data:KRlMK35PPFBTe7FOkbanuskbA4oFj51Fg290lRtwyHKoJxi7fHg7cueojwCiRSJestRguwV8g9UP4MC9bKzWssdFqvfdr7XEUuA3a+WWD9I=,iv:RZhJJS6tNZHecxn/862nnl8dg8OwsVYB/R0yPxYMXgw=,tag:dqXgcU8OSyJzOPJp+7Z+cA==,type:comment]
LITESTREAM_R2_BUCKET=
LITESTREAM_R2_ACCESS_KEY_ID=
LITESTREAM_R2_SECRET_ACCESS_KEY=
LITESTREAM_R2_ENDPOINT=
#ENC[AES256_GCM,data:1BAAp6TJWo4w47vsPtE=,iv:mMZHNSUPmFYK+jLv7DJ4QqZ+wu4mm+QJJxNKxVSiXaM=,tag:rqg9uSb26e3YmL2KIGhsHg==,type:comment]
DUCKDB_PATH=ENC[AES256_GCM,data:QupAI4arYuggsPTVJ2E9BGt3Yhco,iv:nuXFZUleLIIVf5bXXKuQ174psZZjR8AgwNo677A1Kx0=,tag:+9bn+OTtBCmxZqPt0cYCzg==,type:str]
SERVING_DUCKDB_PATH=ENC[AES256_GCM,data:okf9kDEFoPYreiBk1rEoB/6dAFUr,iv:iE+AvfUPX2jxKKBQG9iVMu4LkDcNTxLB9sHY+bmLrso=,tag:GeVRiwbScPrUSsZ1WtfN1g==,type:str]
LANDING_DIR=ENC[AES256_GCM,data:cMnL22EkJGT+jAgM,iv:nItexm3BrtgUVU7TBjHKxBIMuXnuEoAvZcEFFGTmhSI=,tag:E+uXdhTGjKRpjCtRXgcUCA==,type:str]
#ENC[AES256_GCM,data:Cwg5GJ0vOj3LfvtUHVoePytBmvCqJZbqJ5AWhdHcbVFpFVVDYo6GQARMlaLvlEgTe+4mxiR1BgDn6jTokWvynBxgVvQbNLFUINY=,iv:p0fjB0/TQRwdtSxTqFZPtAz9CFRvNjYwxqFLDw9wiko=,tag:EyUfEr0z4PtwvWSo9LbLkA==,type:comment]
REPO_DIR=ENC[AES256_GCM,data:/A==,iv:gTBC1pW2sn/8ZwU2UWErJSecIGmnl5voru0T/klGHuw=,tag:NlFer7SSK9KyAFhrzwv/DQ==,type:str]
WORKFLOWS_PATH=ENC[AES256_GCM,data:lu7JrtxM1TGqY4EErXD13hHMxr4XJg51h2uzXAAFxQ==,iv:j2azHovy7Cu6CREn+cw5hNZkknA5m++lukJskWi7OXU=,tag:d+FSm+hx06SfpD9o7pwr8Q==,type:str]
#ENC[AES256_GCM,data:4To0MRZIt3HxO7qjh4E=,iv:/caczOlTPECDF6mA1PKO8Xm4NeR1RZjgpt2Vuq+rfkQ=,tag:S/UGMqHZQX/Q20N+Ah30WQ==,type:comment]
DUCKDB_PATH=ENC[AES256_GCM,data:sql4dtOLeX1aY/kdaxAzCk47hm3t,iv:S63x40+5blcF8qYxMjqUhs2moukuy2yEQRPbUvXZSYo=,tag:lTLYjtyZNiv06o/hm6Grxg==,type:str]
SERVING_DUCKDB_PATH=ENC[AES256_GCM,data:xE05ajjqmYggI9oz4w1GBucUn0bI,iv:/C3D+iWSNk1XJ/xclTzdJTqOHR12Gwmo1xIxH/4nyL0=,tag:eNcgrb+QvL/y1jE8mb0DHg==,type:str]
LANDING_DIR=ENC[AES256_GCM,data:PNPOE7/MV/iQ24mf,iv:lg486nzb/vlOyTHVQ0HEO4fK18IEJNnuSc/CrQwUsHk=,tag:zecZp+Xfw+dL5GtUeIOg/A==,type:str]
#ENC[AES256_GCM,data:bsiiPYvTz0LtdIgopkPEtcgmtDzZU0W6uton/sqm++5UymV33B0m47LIpdH9xQurQtmoZwMCBkAe0FCqqz62D1dAIH1Q6lzzLqg=,iv:rr7aShvtJtAnBzcbr/O0wOONpDBzwbR/Wbx/YPPsKpM=,tag:YH1wdokUuudFvagnPuT8aA==,type:comment]
REPO_DIR=ENC[AES256_GCM,data:vg==,iv:TNMZ6lrajWy6C9q89/AbRkBawBc2YaGsn2elbO8V2Wk=,tag:va77fkt8VDpPG8pZu490uw==,type:str]
WORKFLOWS_PATH=ENC[AES256_GCM,data:PehxEUMb1K3F1557BY3IqKD7sbJcoaIjnQvboBRJ1g==,iv:WfniguOksC3onCSyDlBpfKC8bE9DAt7evoeYX0K0lvE=,tag:sdRWDqkk9dtuESvfbRBfCQ==,type:str]
ALERT_WEBHOOK_URL=
NTFY_TOKEN=
#ENC[AES256_GCM,data:cz9SOffDAaXZRjw=,iv:7D7YZAyEk5CNlTiL1+KnbPbqfRYMxdtSk40LWErVOfg=,tag:JRHq+gaWSl2h71biklMMwg==,type:comment]
#ENC[AES256_GCM,data:BCyQYjRnTx8yW9A=,iv:4OPCP+xzRLUJrpoFewVnbZRKnZH4sAbV76SM//2k5wU=,tag:HxwEp7VFVZUN/VjPiL/+Vw==,type:comment]
PROXY_URLS=
EXTRACT_WORKERS=ENC[AES256_GCM,data:sA==,iv:cZ3Ga4VPJfTlKrKeHIXadW7kZI9RqkkriKHAxGT5mqw=,tag:4kTYW7QlCwTkFWHxsl59zQ==,type:str]
RECHECK_WINDOW_MINUTES=ENC[AES256_GCM,data:RV8=,iv:Jrom3R7f1NYbEL+lzypeUmifhGaayY3+uzjRuBxzoxs=,tag:pjYanguedj9RMnDGKiF7Yw==,type:str]
RECHECK_WINDOW_MINUTES=ENC[AES256_GCM,data:YWM=,iv:iY5+uMazLAFdwyLT7Gr7MaF1QHBIgHuoi6nF2VbSsOA=,tag:dc6AmuJdTQ55gVe16uzs6A==,type:str]
PROXY_URLS_FALLBACK=
CIRCUIT_BREAKER_THRESHOLD=
#ENC[AES256_GCM,data:cPEkskKyxJENcKo0sFupC9R9qq5bQp7sYT9TdQy06FfHPoDQuWw+JuZ5Bs6pOli4NNQBrPX9fdvRwL1TsqmfajHxrSfGgr3l,iv:wF3I5Y8UzYrrJrIeokXn0P2E51eXnqVFdo8lXpKHZGk=,tag:oTPO6+UjI3ZBY5gOf9RLsQ==,type:comment]
#ENC[AES256_GCM,data:ZcX/OEbrMfKizIQYq3CYGnvzeTEX7KsmQaz2+Jj1rG5tbTy2aljQBIEkjtiwuo8NsNAD+FhIGRGVfBmKe1CAKME1MuiCbgSG,iv:4BSkeD3jZFawP09qECcqyuiWcDnCNSgbIjBATYhazq4=,tag:Ep1d2Uk700MOlWcLWaQ/ig==,type:comment]
GSC_SERVICE_ACCOUNT_PATH=
GSC_SITE_URL=
BING_WEBMASTER_API_KEY=
BING_SITE_URL=
#ENC[AES256_GCM,data:CHMw0ywPH0adeYkcwSndr3JdWyw8f9AdQXQYG62SRCg=,iv:V73eodJud6Z7U8FvuTM52s/2nqNkFz9eneYpPC8OzJM=,tag:obnBC2ERQ19xj8gI8jOosQ==,type:comment]
GEONAMES_USERNAME=ENC[AES256_GCM,data:mLFHQ76lAa2Ygtc=,iv:XWAkwQ075Ph+8qSNmD36PyvPomROENvb3SebVEuVoZg=,tag:cOyW28h6h8nhTbaBZqhmZQ==,type:str]
#ENC[AES256_GCM,data:ECsuDMQipS6YmFpSm1vqCsR2fUW2zN1Mg9VcUlw0roM=,iv:j+F6Akx2bklGMkFTux230YcZjMibA+Qp+qvgkGXl4Jw=,tag:7aO0wbmP/qB73wLgtiSJ2w==,type:comment]
GEONAMES_USERNAME=ENC[AES256_GCM,data:aSkVdLNrhiF6tlg=,iv:eemFGwDIv3EG/P3lVHGZj96MieIsr85e4xYmEIpZyfM=,tag:McpZMNOIO3FDkSebae2gOQ==,type:str]
CENSUS_API_KEY=
sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2L2dtZFVnU3BlODk3WXRQ\nOGxSaTBZSXpBc1lpcUkxSHI5dmlyYUo1K0NFClpycmREMTQxNnIyWnpHWVZOWmFx\nUTNRZDFzcFArMVAvckNBbXJMRVBudHcKLS0tIFRhWWQrNkdVTzlucG5nOVJXUVc2\nREFpWHdpV081TFZON1R2ZDlGNHVsWjQKSgmj4hrVEvrIizGmTpgj93ct1a3lUYXl\nBbuPUT8k+Hj5UmP+SoZqNS3kh2a1Nvr17K6e4PjfRAcEfM0UgNA7Jw==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxNWNmUzVNUGdWRnE0ZFpF\nM0JQZWZ3UDdEVzlwTmIxakxOZXBkT2x2ZlNrClRtV2M3S2daSGxUZmFDSWQ2Nmh4\neU51QndFcUxlSE00RFovOVJTcDZmUUUKLS0tIDcvL3hRMDRoMWZZSXljNzA3WG5o\nMWFic21MV0krMzlIaldBTVU0ZDdlTE0K7euGQtA+9lHNws+x7TMCArZamm9att96\nL8cXoUDWe5fNI5+M1bXReqVfNwPTwZsV6j/+ZtYKybklIzWz02Ex4A==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_0__map_recipient=age1f5002gj4s78jju45jd28kuejtcfhn5cdujz885fl7z2p9ym68pnsgky87a
sops_lastmodified=2026-02-24T15:38:25Z
sops_mac=ENC[AES256_GCM,data:eZOqrSiA4f6mYUaYPS6TD6vL2ON1DsLchIjzSE7bcGpZuaTspItlkBNUR6bsiPnhZ+RCv0xfFMvWallLJe4Y/8ftlQCeq2fGLJ30ZlktgrBocXw5ZYUcJz99NjAXf5gvXoq7Bn5DPnX81ju2a2D8YIhGCZ4YzzE+ae0b44MK9zg=,iv:BG/M2ugqhacqm7dEaHmH+v3dTbu7aKojRjsQBSy/8vE=,tag:1zSJgTCzBUKVsahvdriQrg==,type:str]
sops_lastmodified=2026-02-24T21:27:19Z
sops_mac=ENC[AES256_GCM,data:KuL4wOGAEnMeXEDUKH7MXPhRFln4jTMKJAikTmkyYYxlFsxbTy3o+i5wwpfEZ7oqq/76v7XE2rhg9KMMLfnbZ2rLH9I/6kJRDtlZUUBCdKI6FCRnFbsgmzhuoXMHuFrj4B054u/C8QN2YwL7Mke+Gs9fglxvBrmhN58JAIOaxew=,iv:qu7rdFffw8IBHRP9a1tpPlRexg0b2f6lcpLu9AVbl5k=,tag:h7NbJ4bl/B8/CGVM/iW1Uw==,type:str]
sops_unencrypted_suffix=_unencrypted
sops_version=3.12.1

View File

@@ -1,62 +1,61 @@
#ENC[AES256_GCM,data:ucMhtQ==,iv:sGhlYo+lSjTp5nwwZTSgMqT64ut4T80hx5CVT+g82lY=,tag:RMnG4i6LpK1Y5Bw4gFPqjw==,type:comment]
APP_NAME=ENC[AES256_GCM,data:qruXhXS0DfkEbgM=,iv:tlyiDXsNaIj5vHBaO0dE7mVi2c/IBsLBpsEgibS8DyA=,tag:qnWKM1VcaO3JsIfHz7qo/w==,type:str]
SECRET_KEY=ENC[AES256_GCM,data:9bXIuM5FOXgp,iv:/df/NFPVVNpCtWSWdxfn5UkEeRmbtmJ1coMHvG6c414=,tag:wOtxv/ftApPR07ywoIvO4w==,type:str]
BASE_URL=ENC[AES256_GCM,data:C7l7voU3GttiIRbAZ3/dhHootWm7wQ==,iv:HyDI4yfZkBuRuvUUao//mu6nkfW/lyKDdXS472pJuK8=,tag:IXC5Xpe1YcEOCCTsnBuNDg==,type:str]
DEBUG=ENC[AES256_GCM,data:Aq7nwAo=,iv:px2NR94oiodO8FbCa+VMNptNR51sHavOmiQBQ667pVg=,tag:vHIwuM+sg2Lpvw+ZUMZVRw==,type:str]
#ENC[AES256_GCM,data:Bf/QsEOoDh1gfJIHwA==,iv:nSoT2Bnk9y2VxoL2opvUrSBImRstydELaSk2IO9NYPE=,tag:YAqhk8/qpW4UsMsjdS+RAw==,type:comment]
ADMIN_EMAILS=ENC[AES256_GCM,data:CDh9bd1OesYs,iv:C6Dwn2h6BYXc21VBFYplpfhwNj8TPevSRvkPCarL7eo=,tag:BibcNChGFh1b2jCF67Nn0A==,type:str]
#ENC[AES256_GCM,data:56tQlB/WNuue,iv:lh7+zHQuoAC9jDEgI6/g41H/9gj544nDOwAYcFWjpQs=,tag:XIVb5LJKxlSQz5qPidwJQw==,type:comment]
DATABASE_PATH=ENC[AES256_GCM,data:itpuoRhwDXFgEIg=,iv:2/UkQmyyzd3jaUgcxbMCmsflN9ubY+T/y3U9DIj0+3I=,tag:mLONYoV1YRldPS4fjmWo0A==,type:str]
#ENC[AES256_GCM,data:3AMoLpE=,iv:w3+deBCRpccgTepZ7/j36pkzUIWAmaM3KuJVpeN1qiA=,tag:V9cfSO0NOKy1WLVQ4OSQYA==,type:comment]
MAGIC_LINK_EXPIRY_MINUTES=ENC[AES256_GCM,data:QZ8=,iv:0KWT8VtITdDyBTM41wK4Xe29vbwbVXq5JI+Bk1C0zLk=,tag:y3DG33dd3YLhCC3RHfvJJw==,type:str]
SESSION_LIFETIME_DAYS=ENC[AES256_GCM,data:J0Y=,iv:CTSBzRzrn5EHO7eNQsZH55vPx1l00WfaQ2tQOQPbNxY=,tag:jvP5sAHd/MkGtzQ5tJc3jw==,type:str]
#ENC[AES256_GCM,data:4AzExSrkvf6tPpvTuvhD,iv:WZBGtFORarHjnBVZbyIzeeY4qFePnrEfUVFIGshiytI=,tag:grHkOyLwjcti7sHvzSdVSg==,type:comment]
RESEND_API_KEY=ENC[AES256_GCM,data:7s9gnzHzzYNy,iv:+2c0tLkLGwx15iLBzlCK+NO0XLLOoar90KRXqN/HwuQ=,tag:2gYY2jxVRYvt5MpBCWb3Jg==,type:str]
EMAIL_FROM=ENC[AES256_GCM,data:66oS65zkYQJ4BXh9clfF861fwsR09gVgRT0hwZegpnURwA==,iv:9fTh7YU+DzIP6Cj+unxuzJa0mnHsHcwNfvhI6zffjC0=,tag:ZLaPF45Ns0F3xNynXW42uw==,type:str]
LEADS_EMAIL=ENC[AES256_GCM,data:SkoYDLDQOCWLHGPFd6HQ1cCU/VHuU9jK9FSjNMHKxnCbXw==,iv:kt4tkw2BJF+Fz5oquje3OvMosqculK8Kxm6h30LWxj0=,tag:PSy1qSkCV+Z/z8dYGLV3BA==,type:str]
RESEND_WEBHOOK_SECRET=ENC[AES256_GCM,data:M0BNhZKQvfdT,iv:XIGForPlTQl3NO+hUp90D7sW+wZz4CmCWvPKHedL9MA=,tag:wbxHr0YBKKMOt8tGYG0dVQ==,type:str]
#ENC[AES256_GCM,data:XU7LmjtgBw==,iv:mTo7c7tQ4bCrUpRjfpkl/eTMv9qgVVwG2BwDJjDENng=,tag:pJlSVRi3sj1CgapPKDmcMw==,type:comment]
PADDLE_API_KEY=ENC[AES256_GCM,data:F/VGqmpu5Pja,iv:RIIaP3LsvnQ3pPQ4OpXlzz2N3vYnQEyrwFrukpHY3qs=,tag:MZJYLxddceccoAPgmW2tgA==,type:str]
PADDLE_CLIENT_TOKEN=ENC[AES256_GCM,data:sMUzWxIx835F,iv:mXc20kRmnofJf4Th2O4sjJoyTAlKHUbmbkd3tl19VkA=,tag:a3/N0KT3v1bo/o65sTuB+A==,type:str]
PADDLE_WEBHOOK_SECRET=ENC[AES256_GCM,data:AQ5VbLqVyoVr,iv:tqloKV/Vfo3P05QZDsc8p0bfnwcylsQgVjhF17AyE7U=,tag:7gpQEQVcxOu8YgN/518u/w==,type:str]
PADDLE_NOTIFICATION_SETTING_ID=ENC[AES256_GCM,data:ZBhOIvcGpGWY,iv:ByQcuU88DjAUEs4x++8+3E80vyiDWqbA6VR4bG5oZuU=,tag:TXnesiQ7K+baSOH6XlzBPA==,type:str]
PADDLE_ENVIRONMENT=ENC[AES256_GCM,data:8Ayb93UcbMDSAg==,iv:DydRKcY3zHa30+L6g/2ooDZbtyMHy3yJ1ETRssqDkFs=,tag:1nqgd26CAeB6HQEGHQr16g==,type:str]
#ENC[AES256_GCM,data:c1C8AUiw,iv:vU1muGR79S+rr5dTQbzDEYZ5WZdpB2zaHEcEvPIgPYU=,tag:vr07Boz2lZtBscvlHGt10g==,type:comment]
UMAMI_API_URL=ENC[AES256_GCM,data:uZMJ+vSyXZkgJPRwY67HTzKCA5qA9vMp4lmCBw==,iv:/SuiWslYHayfB4eaJ4rOtqv/CFBt2GbtOe/83ZYvCxM=,tag:y0aJ/GVhZigxAHOklmLg9Q==,type:str]
UMAMI_API_TOKEN=ENC[AES256_GCM,data:aYqT3Xwytvrl,iv:MRei8ZxgohwsbDyP2xruEDdiZQaGA41IlSeb4oqr93A=,tag:0VnkdreND5HggCA0LS+sRg==,type:str]
#ENC[AES256_GCM,data:3QFdBeiJqY3UfkClvPs=,iv:2OUB0JZbwSwFOiNo4GO5fTF6WwSD++Gy9iy6EoH8VGM=,tag:mEszf5Zgvv4bUGE7Iqhf+g==,type:comment]
RATE_LIMIT_REQUESTS=ENC[AES256_GCM,data:gPCG,iv:AC3g0YDWdQRexRbod3m8UXNKzy/qn0C4LOy5kNCC3cc=,tag:pX9JwjdauMQkkcddYvk9Dg==,type:str]
RATE_LIMIT_WINDOW=ENC[AES256_GCM,data:S2Y=,iv:PzZDhpC06Vh8qZ2/ImgIIp8ENUhEIHkyzTi3Ob+PWw0=,tag:5hpdFo0nJaSUoA63inq3jg==,type:str]
#ENC[AES256_GCM,data:DS4SYOlYWDPAzQe9TbFKC4hSfPgt,iv:HI0pGyQnnBIo6Ufb5QlT6539QVgLNd3Q1E0nVZT2YNw=,tag:VbcykF5tPDULflTGSBw9Bg==,type:comment]
LITESTREAM_R2_BUCKET=ENC[AES256_GCM,data:N/buXMd8Bmen,iv:AFvbKwo+oipuFOB4noaks//IQ92I7gvalUgLYJmp3h0=,tag:6nljZEU+01I2A6bYmHf3XA==,type:str]
LITESTREAM_R2_ACCESS_KEY_ID=ENC[AES256_GCM,data:AJujAQyPg+7i,iv:x3sC5WeoUtnJGN01J7p+8W5q8QCbI7g8kA6+njdgsHA=,tag:WUAjGE8rTizRppwl4zR3Xw==,type:str]
LITESTREAM_R2_SECRET_ACCESS_KEY=ENC[AES256_GCM,data:0uAA0+aYhDPS,iv:h3+1Tb7Z8JU+N5MsNOYy9oKfMZirFL1j8q0sCwol3bE=,tag:kUcuX79/CkFx8vXRq9LzaA==,type:str]
LITESTREAM_R2_ENDPOINT=ENC[AES256_GCM,data:LevPHY6+xQzE,iv:YKSlo15j2JOpaDFE3fodV2xzrFPma23LoRtbmrcAwKk=,tag:lRKpLojIj91NP3rQj0lujg==,type:str]
#ENC[AES256_GCM,data:hCAkcPu59qPCG+gdRZc=,iv:fsXe8zekkwZsVyKhD15gJUy+nrmlkE3y5GTSxnrsSBI=,tag:QzuZ3hjg0RP5ydk9LLqZtQ==,type:comment]
DUCKDB_PATH=ENC[AES256_GCM,data:7ovwg981vYaSxbPLhliEGiE+f/8V,iv:8+sT3EGhN3qPAGXehVXFibxGqebShA4+fpV8PMH89RY=,tag:Ed6JR6X661riZ19K1Rka4g==,type:str]
SERVING_DUCKDB_PATH=ENC[AES256_GCM,data:gxDrCU7+J4hvzJGXPjxsvjZdJx7R,iv:ig+32NjlalAebrl24/V2L9cvtAGxCFLci/b9nBVsmrk=,tag:oJVU7BX7qMp++tGGYNxzqg==,type:str]
LANDING_DIR=ENC[AES256_GCM,data:Pz7vkNm/xxdO+kn9,iv:QleME3pY9gwgDmW6Vly1LVRMWhdkD04BXyzO3gFX3YM=,tag:QOpMsiXccD7xPsNJ/uuHjg==,type:str]
#ENC[AES256_GCM,data:AQyf+O/gIVE40EU=,iv:uJwMEr44+W4hjRUMPoIhofJfWvXxJDQStRLyjGDdw2w=,tag:Ry07aeuhb6d4CXhpcFkv6A==,type:comment]
REPO_DIR=ENC[AES256_GCM,data:yKOuO4XPNcPM14ZnKgLxpg==,iv:JJIkIHqDw7xessJZtwdxhp56UT9f7KtAHT1Hyi7Zd3A=,tag:PYMuH418TtcMuLBwrxDGsA==,type:str]
WORKFLOWS_PATH=ENC[AES256_GCM,data:tunk/tbrbvhMHONwRHV1A2l2da50L4n4CeJly3fz9g==,iv:WvxDglP2QRpgOl+RelF2a+JuPvjwusvet4xZs2s+tp8=,tag:CJuzy6A0vUbXd2e5+BXNEQ==,type:str]
ALERT_WEBHOOK_URL=ENC[AES256_GCM,data:oHSBbRbq9tCueTxoEJiTmKVJoBIERiV75rsHhUts2Jo=,iv:qm7O2GJ3Rlp3LE1PdQXZPzlO0lropGEe5Wr+28F05Cs=,tag:5Ha/2D4G3NjiqkCE1NjrEw==,type:str]
NTFY_TOKEN=ENC[AES256_GCM,data:jIWqTX+iEzUvjJbSKJIZ7ZzZn0YbM7+4RU1W16D6j2U=,iv:R6be5ijLBLUNZjxHO2YkbgjjQDZdjD8gGRJedcFRI60=,tag:K2GL+O5TjdnIgC5l7pG0tg==,type:str]
SUPERVISOR_GIT_PULL=ENC[AES256_GCM,data:HQ==,iv:ZBSitlE8BIhM63+f3niABpM5kUmd07cg66icuVlGzc4=,tag:vxMBFQiuXmaKfeQtkx8oAQ==,type:str]
#ENC[AES256_GCM,data:5IbMzndnVQPyc8g=,iv:jrHRyj1c+AUJ5Jb8Omb3aliG0j0q850wIjA9tIqKbzI=,tag:n1if0sch0E1mBOp3qr2+zg==,type:comment]
PROXY_URLS=ENC[AES256_GCM,data:g8/iWdCPfTVt,iv:ZGvbYkfZk64Y2CC4vuGCj7TpRJGsSOP/psjz2pgKzow=,tag:GYvlKB1xn328bmpBN24W4g==,type:str]
EXTRACT_WORKERS=ENC[AES256_GCM,data:GQ==,iv:mUT35A3XBGaBox2PImgeWZyQx1AMQcPTnS4NJi1QnlI=,tag:dG/ZF2xlGsEJBBvfyG0hZg==,type:str]
RECHECK_WINDOW_MINUTES=ENC[AES256_GCM,data:vi4=,iv:2oPRzyrFgIwOGjEH13P/7VQACA3xqDOz8+O7cDUnPwI=,tag:IFh7z+ZF+zjoADH0gFrPXg==,type:str]
#ENC[AES256_GCM,data:cG6Bl04wlNIwNTjP5TSykDI=,iv:qOrJNlej+elCvc7paLRL50opAD7zSeHYmIwAeFuH11s=,tag:P1dTLqa/DSMjIFvDTZZqhQ==,type:comment]
GSC_SERVICE_ACCOUNT_PATH=ENC[AES256_GCM,data:wqtE1aoqcK6v,iv:QejEYIbxDcYDiFC9Wdes81cYx2NL3b9o0v0XVRh7G1w=,tag:d3u6Rf8ptOhM/4pwxtg+6A==,type:str]
GSC_SITE_URL=ENC[AES256_GCM,data:25zMmaOduZznbTQwO29huAo7xFq3Ow==,iv:ahq19rDzdx5PB/5YyHxZc7EPAeHya7loe3cdGm5ot+M=,tag:aVmC7IKkqYo8lAH1T1XDQA==,type:str]
BING_WEBMASTER_API_KEY=ENC[AES256_GCM,data:pKZGODRwoo4D,iv:tPsrHU1B10lUkVJza2hub0lGAQ15xFZVePZ8RPI1XWo=,tag:zdWhYljkhnKAKRObOfII2A==,type:str]
BING_SITE_URL=ENC[AES256_GCM,data:VyIcIcxveu+dWz3zY6h/JVLjPw7ysw==,iv:Wj1TU7r9Izfyexp4WdoByRP+l01ZWml1mNgp6ys28EQ=,tag:fbC8Q7yFGeZBdiiDBADLwQ==,type:str]
#ENC[AES256_GCM,data:CDAjB0UL7OjgRPMmu97Z5HHjE4o4idn4Pb3N8/y8KHc=,iv:5ELBfYuFLZblCNMjPpZ10UxQqp9CzAIZQt7iSQwdR54=,tag:NguW5ISLMS5xpXSWfpJaIA==,type:comment]
GEONAMES_USERNAME=ENC[AES256_GCM,data:eaQPCcEreqBdHcw=,iv:CKD9cnL2BOn/yJM5EQs0Y044bAN3d4I6bRyTqhIQkns=,tag:82w/yCiGfKsV8zhpINL29g==,type:str]
#ENC[AES256_GCM,data:8qKvOA==,iv:Xci2F8lcBpT7dmhzaDe6sfrtQi+yQD7e2CQsYLAdCnY=,tag:3duziYwr7PoGQILUuY8nBA==,type:comment]
APP_NAME=ENC[AES256_GCM,data:ldJf4P0iD9ziMVg=,iv:hiVl2whhd02yZCafzBfbxX5/EU/suvzO4kSiWho2oUo=,tag:qzrr57sTPX8HPyDVwVL4sw==,type:str]
SECRET_KEY=ENC[AES256_GCM,data:Pll2sBGZsUJ0,iv:Dz+rq47dV3TmJXIQu+P+TmKXKFYsxbkY7/5js1cPrWA=,tag:IVAValYSELDRUMisbMwbAQ==,type:str]
BASE_URL=ENC[AES256_GCM,data:50k/RqlZ1EHqGM4UkSmTaCsuJgyU4w==,iv:f8zKr2jkts4RsawA97hzICHwj9Quzgp+Dw8AhQ7GSWA=,tag:9KhNvwmoOtDyuIql7okeew==,type:str]
DEBUG=ENC[AES256_GCM,data:O0/uRF4=,iv:cZ+vyUuXjQOYYRf4l8lWS3JIWqL/w3pnlCTDPAZpB1E=,tag:OmJE9oJpzYzth0xwaMqADQ==,type:str]
#ENC[AES256_GCM,data:xmJc6WTb3yumHzvLeA==,iv:9jKuYaDgm4zR/DTswIMwsajV0s5UTe+AOX4Sue0GPCs=,tag:b/7H9js1HmFYjuQE4zJz8w==,type:comment]
ADMIN_EMAILS=ENC[AES256_GCM,data:dtEDXPbN5Y5q,iv:k1GSkJh+L4kOM8V0cGYnz0/CsmvwdVRNHk0qpBulSS0=,tag:rUpVgROj2qD8a5IufnBrJw==,type:str]
#ENC[AES256_GCM,data:S7Pdg9tcom3N,iv:OjmYk3pqbZHKPS1Y06w1y8BE7CU0y6Vx2wnio9tEhus=,tag:YAOGbrHQ+UOcdSQFWdiCDA==,type:comment]
DATABASE_PATH=ENC[AES256_GCM,data:qxQs7dG0RWMA1rs=,iv:5ZUyk02hCPQESr2vFz3mfnUhUF74LbO6YK5+HFBbxUQ=,tag:daQxiWAhzCB2cScjzjYwaA==,type:str]
#ENC[AES256_GCM,data:aWgKm9Y=,iv:8iT6GHSzWhM+fRX9PIY9wAs7lXj/ADS6eZK9BBSEdaQ=,tag:aSLsj52ybnod7Qfmx9BLQA==,type:comment]
MAGIC_LINK_EXPIRY_MINUTES=ENC[AES256_GCM,data:YSE=,iv:GYm1EWku7+OG+fCIbUHWsfYbnEQVNhlBmWBC1OCV1NA=,tag:L2kdm7tMWOO/cf+VDd+OdQ==,type:str]
SESSION_LIFETIME_DAYS=ENC[AES256_GCM,data:9Og=,iv:3nStZVZVB24aAtNrtLXZ0oIehTDyu2IzdXoMH59t+3o=,tag:+FQ4n1XeSS12zUGXt/1RKQ==,type:str]
#ENC[AES256_GCM,data:mtqp/c5zZxlcB4HrOrfi,iv:eJaN+ZnAIaNHF5iovcz0QynILq9GjqVcwoyN2ZhLmpI=,tag:WyXU7ho5T/CE609id9dOzA==,type:comment]
RESEND_API_KEY=ENC[AES256_GCM,data:U5aEnItbJ/Af,iv:7BTFimeMbPtK6ANXMr7VwO5TJ7IaRk+HAOZy+TEXMVI=,tag:sDhW5icVloSck1iafu3H0A==,type:str]
EMAIL_FROM=ENC[AES256_GCM,data:BTGeWUjG9qCBvRQr9kK5sfdzQ1CfuNgpkU/AL3Qu6GJ2ng==,iv:0XjqD8hCqleSJR2FrDajlnUul8o4GkK0f1MOP96MRkw=,tag:0PwZwxuBbUFYdiRYTlDffg==,type:str]
LEADS_EMAIL=ENC[AES256_GCM,data:jkpWqodUgR2QoB96zvE5aH/tA9Sh0nPcl75P3i43ecFILw==,iv:vNtB/9gdrTDm6vNIjnH6JShYyqmG7h9jd2uzwFwjhO8=,tag:cG5T3CwQfZO/jTYFnwJSgA==,type:str]
RESEND_WEBHOOK_SECRET=ENC[AES256_GCM,data:EQpvkWFyt8H7,iv:6QiZIDo5Ps39vf9MKkiqSJir7BH9zhoLREJ425y3FIs=,tag:kjO4dczb2E5FKfO6OVaQvw==,type:str]
#ENC[AES256_GCM,data:HW8JOkd7Hw==,iv:Qfwm2ZHT8TKANrLrRQqHnceQVUTiuzT2hSjLN8hSq5Q=,tag:hvVLmGGUBRlsm2qy9jxIvA==,type:comment]
PADDLE_API_KEY=ENC[AES256_GCM,data:d3rKjWFrFepp,iv:TGjG9VTC4pZFgnp5daE+jBrRCUJddqgRaV7rQ61llhU=,tag:KKaYPfUgLC58zhC8s3B4cQ==,type:str]
PADDLE_CLIENT_TOKEN=ENC[AES256_GCM,data:JPmeLZx16WuV,iv:52EczBQM+fvEQuzoY8Aon0RBZiLzf1vrbT9Kx+b/WUE=,tag:+abUTzCgxulamobp13PbWQ==,type:str]
PADDLE_WEBHOOK_SECRET=ENC[AES256_GCM,data:fk2PbtpwoGRB,iv:QOhOd4rKmVjMA1EUQUjSj/y/OM7I435K/s4aqShjQNw=,tag:RIfbUCXAQGmCiE9FODHgpA==,type:str]
PADDLE_NOTIFICATION_SETTING_ID=ENC[AES256_GCM,data:igRsm8JOO1SP,iv:vQgOZcMHt6YoE+U2d6tT8sILOwsTx3glHVBBatR6Sk8=,tag:1tApDyZmZNiwd3bVm0uZGw==,type:str]
PADDLE_ENVIRONMENT=ENC[AES256_GCM,data:A1qXlv+9hjdIug==,iv:nu9kRQZgGLFXXT2I5GaRzp13YgQxU2ucr9azEA4XTUQ=,tag:RBxwE2j9v/RCiEMIa+6ICw==,type:str]
#ENC[AES256_GCM,data:F3dSfSGV,iv:Zjzmp9Vb+LBkqV6xBIMF2cK8ON9crH3fHcOog4+LOpo=,tag:7V8E9ChwYY9ceTaYdg3Lbw==,type:comment]
UMAMI_API_URL=ENC[AES256_GCM,data:4nJZc/opX4rsqAxO6XxD1Es5ySMh7nUtcGt6Kg==,iv:DcmhRe1IJKS0tOFgdJQQv2A1kO5K8VVT8aW0Vq5hVlY=,tag:Sglu4nnAiLIzr+ovJ/hEKQ==,type:str]
UMAMI_API_TOKEN=ENC[AES256_GCM,data:Xv1eTWtiJ6PL,iv:9sYsI2dJaQt6gpC/ev0b2dSk48PzuojTg18xXnBSWvk=,tag:DAMDHk0b9IG7T9MpkpzAkQ==,type:str]
#ENC[AES256_GCM,data:wAePRqqMZL2oCJB812A=,iv:jaLmjd0GW2dnEQ3KgWcvAs7Q7aDwlCexM9W7pH27kss=,tag:h7/yIdc13+3pmqyCc0OPkg==,type:comment]
RATE_LIMIT_REQUESTS=ENC[AES256_GCM,data:W3Nt,iv:ycMAxrPq44S6qezQIa50rc7GDplo1YvAO6VUERGQUxA=,tag:uzendLuSVbmSPcVPEgLiqQ==,type:str]
RATE_LIMIT_WINDOW=ENC[AES256_GCM,data:r8o=,iv:m5uKo3N8mb7FWI70SgaaHSyC3CNeD8XxjEx8ENit9uI=,tag:gKXEXsIwtBr3sm7xqLRHIw==,type:str]
#ENC[AES256_GCM,data:E6JgKjxuqFdPtVEv6Xiz1kqcT4ar,iv:hL7P7/X7nEqFwnlf72QEeHhViQ17HZbsCP/M4gcTJiA=,tag:FjCPSvrBboCWjfIS/fab0A==,type:comment]
LITESTREAM_R2_BUCKET=ENC[AES256_GCM,data:opg8kQY3PKnZ,iv:lPHUBDwHgBulOyt9WWgZhBQae8t2WKYvLHSFQrG3N/w=,tag:qtyIz4fbh40aLp7ZawBJiA==,type:str]
LITESTREAM_R2_ACCESS_KEY_ID=ENC[AES256_GCM,data:6jaEysPtRal7,iv:s5aLx7LdZ3ZLA9oL5vXXDfDDGI7gd5/CukNrMpPLJNk=,tag:Igp3bqW52raBfEeUaUvZ7A==,type:str]
LITESTREAM_R2_SECRET_ACCESS_KEY=ENC[AES256_GCM,data:QfXhwh9L2rhr,iv:OaYlzTiu4onCNu5HfytYTCJa5p2QLShhO5j5Y038IOs=,tag:i13aQ2ICePyCU/Ob+EA7Nw==,type:str]
LITESTREAM_R2_ENDPOINT=ENC[AES256_GCM,data:hLneNsFmgQ6+,iv:RNefJ3QbviHPURxcK2xYJU7qWpMfWInCxYQ/4xDIwfw=,tag:FhMiHGrNcsXaSmdG4NXgfQ==,type:str]
#ENC[AES256_GCM,data:YGV2exKdGOUkblNZZos=,iv:NuabFM/gNHIzYmDMRZ2tglFYdMPVFuHFGd+AAWvvu6Q=,tag:gZRoNNEmjL9v3nC8j9YkHw==,type:comment]
DUCKDB_PATH=ENC[AES256_GCM,data:GgOEQ5B1KeQrVavhoMU/JGXcVu3H,iv:XY8JiaosxaUDv5PwizrZFWuNKMSOeuE3cfVyp51r++8=,tag:RnoDE5+7WQolFLejfRZ//w==,type:str]
SERVING_DUCKDB_PATH=ENC[AES256_GCM,data:U2X9KmlgnWXM9uCfhHCJ03HMGCLm,iv:KHHdBTq+ct4AG7Jt4zLog/5jbDC7LvHA6KzWNTDS/Yw=,tag:m5uIG/bS4vaBooSYoYa6SA==,type:str]
LANDING_DIR=ENC[AES256_GCM,data:NkEmV8LOwEiN9Sal,iv:mQHBVT6lNoEEEVbl7a5bNN5qoF/LvTyWXQvvkv/z/B0=,tag:IgA5A1nfF91fOBdYxEN71g==,type:str]
#ENC[AES256_GCM,data:jvZYm7ceM4jtNRg=,iv:nuv65SDTZiaVukVZ40seBZevpqP8uiKCgJyQcIrY524=,tag:cq6gB3vmJzJWIXCLHaIc9g==,type:comment]
REPO_DIR=ENC[AES256_GCM,data:ae8i6PpGFaiYFA/gGIhczg==,iv:nmsIRMPJYocIO6Z2Gz4OIzAOvSpdgDYmUaIr2hInFo0=,tag:EmAYG5NujnHg8lPaO/uAnQ==,type:str]
WORKFLOWS_PATH=ENC[AES256_GCM,data:sGU4l68Pbb1thsPyG104mWXWD+zJGTIcR/TqVbPmew==,iv:+xhGkX+ep4kFEAU65ELdDrfjrl/WyuaOi35JI3OB/zM=,tag:brauZhFq8twPXmvhZKjhDQ==,type:str]
ALERT_WEBHOOK_URL=ENC[AES256_GCM,data:4sXQk8zklruC525J279TUUatdDJQ43qweuoPhtpI82Y=,iv:1NT5IsslsZjo/0xU9OGFf717G56FnSkKSZ2L1+U3peU=,tag:bhZ67zlDiq7VaY47LFWOVw==,type:str]
NTFY_TOKEN=ENC[AES256_GCM,data:YlOxhsRJ8P1y4kk6ugWm41iyRCsM6oAWjvbU9lGcD0A=,iv:JZXOvi3wTOPV9A46c7fMiqbszNCvXkOgh9i/H1hob24=,tag:8xnPimgy7sesOAnxhaXmpg==,type:str]
SUPERVISOR_GIT_PULL=ENC[AES256_GCM,data:mg==,iv:KgqMVYj12FjOzWxtA1T0r0pqCDJ6MtHzMjE+4W/W+s4=,tag:czFaOqhHG8nqrQ8AZ8QiGw==,type:str]
#ENC[AES256_GCM,data:hzAZvCWc4RTk290=,iv:RsSI4OpAOQGcFVpfXDZ6t705yWmlO0JEWwWF5uQu9As=,tag:UPqFtA2tXiSa0vzJAv8qXg==,type:comment]
PROXY_URLS=ENC[AES256_GCM,data:L2Oobpi6Pq8m,iv:14mXi+8mLv2e20IKVL0VlxZiHW/1BmeQP4a6ns5930g=,tag:pVJasNjv6N/UApVm+KD+XA==,type:str]
RECHECK_WINDOW_MINUTES=ENC[AES256_GCM,data:L2s=,iv:fV3mCKmK5fxUmIWRePELBDAPTb8JZqasVIhnAl55kYw=,tag:XL+PO6sblz/7WqHC3dtk1w==,type:str]
#ENC[AES256_GCM,data:RC+t2vqLwLjapdAUql8rQls=,iv:Kkiz3ND0g0MRAgcPJysIYMzSQS96Rq+3YP5yO7yWfIY=,tag:Y6TbZd81ihIwn+U515qd1g==,type:comment]
GSC_SERVICE_ACCOUNT_PATH=ENC[AES256_GCM,data:Vki6yHk+gd4n,iv:rxzKvwrGnAkLcpS41EZ097E87NrIpNZGFfl4iXFvr40=,tag:EZkBJpCq5rSpKYVC4H3JHQ==,type:str]
GSC_SITE_URL=ENC[AES256_GCM,data:K0i1xRym+laMP6kgOMEfUyoAn2eNgQ==,iv:kyb+grzFq1e5CG/0NJRO3LkSXexOuCK07uJYApAdWsA=,tag:faljHqYjGTgrR/Zbh27/Yw==,type:str]
BING_WEBMASTER_API_KEY=ENC[AES256_GCM,data:kSQxJOpsYCuJ,iv:Kc4jJpOd64PATeBjidNHTwBr/bNnCeqsTrUqAAYM5Vs=,tag:4jBxqgpyomzMLwiC9XpfVQ==,type:str]
BING_SITE_URL=ENC[AES256_GCM,data:M33VI97DyxH8gRR3ZUXoXg4QrEv5og==,iv:GxZtwfbBVihUbp6XNQKzAalhO1GfQF1l1j1MeEIBCFQ=,tag:9njlBp4v684PeFl3HebyIg==,type:str]
#ENC[AES256_GCM,data:OTUMKNkRW0zrupNppXthwE1oieILhNjM+cjx5hFn69g=,iv:48ID2qtSe9ggD2X+G/iUqp3v2uwEc7fZw8lxHIvVXmk=,tag:okBn0Npk1K9dDOFWA/AB1A==,type:comment]
GEONAMES_USERNAME=ENC[AES256_GCM,data:UXd/S2TzXPiGmLY=,iv:OMURM5E6SFEsaqroUlH76DEnr7C/ujNk9UQnbWT0hK4=,tag:VsjjS12QDbudiEhdAQ/OCQ==,type:str]
CENSUS_API_KEY=
sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWdVBTa1owM0JrbFJXcmg2\nZVNzRHJuK0MzY3gwbVdGZW1oWFh4VU84a3hjCmZWQnAybjVFSituRVE2eWt3QkpI\ndzAzMEpXeld6UEFraEZLUjJGSEordGMKLS0tIGtEbGd3ak82UnJiRjFDQXJvYkVO\nL0xYVW5Ya0U0QUYzckI2MWZyLzU0OUkKK7Q+mN6ew8pdpN7Z3zMQhWm/Lgkzu8Hi\n8i74oE6TfyKFQkhaCu4jOcBfYWTytMe38ZYLI0ApS5AeIsr/ZVtWGA==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqck9GdHVkUmIzNnlvMW5k\nVkNtazZ0ZytzZ25vMU5SckdFLzcrTFNYOVZZCmNjbU9yV0lTRlB5cEpMVC81QTdu\nS2ZDc0ZkNnRBNFhFMEN1bjY3YVhwZEEKLS0tIGE5TEdYenVOV1IwcE0wYnlKNElF\ncXV1K0xuczZzZ3JnL1lrSC9QWHIwNGsKfW4ARke6Cj83BpQc8weayL3v8SVgQ+Fp\n99aVWp103O1fumksR1w4u0X7fSNRrgAmpY/yyZuEvsoIY8ELFVcqgQ==\n-----END AGE ENCRYPTED FILE-----\n
sops_age__list_0__map_recipient=age1f5002gj4s78jju45jd28kuejtcfhn5cdujz885fl7z2p9ym68pnsgky87a
sops_lastmodified=2026-02-24T15:04:59Z
sops_mac=ENC[AES256_GCM,data:BsSyxkjwN8SNSC8fE3iNZPYIAPgrnbMYLGN/waGNkzH11VfcGAw5vQaPR6Il1PBMrx8gJ9daxRbvTW/DkY+G8VTpF3HWB3IoJPRewTLNUdkDSCxwhGuzfTzT1f7FKeNNVxsCEhJZGMYbDiYzcnbU1owgcHivBfCYl0DF0VM8cS0=,iv:aV5Af5nrhaI9NE2ouGnr20s6mRD9VPHLNcdfola9Ybw=,tag:YD08kkuFLksllK4Q9cfYfQ==,type:str]
sops_lastmodified=2026-02-24T21:29:26Z
sops_mac=ENC[AES256_GCM,data:zYvusl8/pvL6FwXAtsKi4BhuiDt8KaZPNHXkw0ywIOgNFG5mvcQozcDj42+TIo+Yuum1o7WHqshKc70w0Mq4fskq3TsjVnjWgw7xYRr5s3ylN5ZknbbCoMP4cp6YrkNCe/8hR64miguYqqEQlf9NdgL52uamF5lV5irI/EtLouw=,iv:RcL2b8ccnMxKhXxAocTG9G6gv2BkTb++MUpkFK8MfbM=,tag:+0avRrQjNOHDUeAV1dLW3g==,type:str]
sops_unencrypted_suffix=_unencrypted
sops_version=3.12.1

View File

@@ -10,7 +10,13 @@ API notes (discovered 2026-02):
- `size=100` is the maximum effective page size
- ~14K venues globally as of Feb 2026
Rate: 1 req / 2 s (see docs/data-sources-inventory.md §1.2).
Parallel mode: when PROXY_URLS is set, fires batch_size = len(proxy_urls)
pages concurrently. Each page gets its own fresh session + proxy. Pages beyond
the last one return empty lists (safe — just triggers the done condition).
Without proxies, falls back to single-threaded with THROTTLE_SECONDS between
pages.
Rate: 1 req / 2 s per IP (see docs/data-sources-inventory.md §1.2).
Landing: {LANDING_DIR}/playtomic/{year}/{month}/tenants.json.gz
"""
@@ -18,11 +24,13 @@ Landing: {LANDING_DIR}/playtomic/{year}/{month}/tenants.json.gz
import json
import sqlite3
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path
import niquests
from ._shared import HTTP_TIMEOUT_SECONDS, run_extractor, setup_logging
from ._shared import HTTP_TIMEOUT_SECONDS, USER_AGENT, run_extractor, setup_logging
from .proxy import load_proxy_urls, make_round_robin_cycler
from .utils import landing_path, write_gzip_atomic
logger = setup_logging("padelnomics.extract.playtomic_tenants")
@@ -35,6 +43,30 @@ PAGE_SIZE = 100
MAX_PAGES = 500 # safety bound — ~50K venues max, well above current ~14K
def _fetch_one_page(proxy_url: str | None, page: int) -> tuple[int, list[dict]]:
"""Fetch a single page using a fresh session with the given proxy.
Returns (page, tenants_list). Raises on HTTP error.
"""
s = niquests.Session()
s.headers["User-Agent"] = USER_AGENT
if proxy_url:
s.proxies = {"http": proxy_url, "https": proxy_url}
params = {"sport_ids": "PADEL", "size": PAGE_SIZE, "page": page}
resp = s.get(PLAYTOMIC_TENANTS_URL, params=params, timeout=HTTP_TIMEOUT_SECONDS)
resp.raise_for_status()
tenants = resp.json()
assert isinstance(tenants, list), f"Expected list from Playtomic API, got {type(tenants)}"
return (page, tenants)
def _fetch_pages_parallel(pages: list[int], next_proxy) -> list[tuple[int, list[dict]]]:
"""Fetch multiple pages concurrently. Returns [(page_num, tenants_list), ...]."""
with ThreadPoolExecutor(max_workers=len(pages)) as pool:
futures = [pool.submit(_fetch_one_page, next_proxy(), p) for p in pages]
return [f.result() for f in as_completed(futures)]
def extract(
landing_dir: Path,
year_month: str,
@@ -46,26 +78,45 @@ def extract(
dest_dir = landing_path(landing_dir, "playtomic", year, month)
dest = dest_dir / "tenants.json.gz"
proxy_urls = load_proxy_urls()
next_proxy = make_round_robin_cycler(proxy_urls) if proxy_urls else None
batch_size = len(proxy_urls) if proxy_urls else 1
if next_proxy:
logger.info("Parallel mode: %d pages per batch (%d proxies)", batch_size, len(proxy_urls))
else:
logger.info("Serial mode: 1 page at a time (no proxies)")
all_tenants: list[dict] = []
seen_ids: set[str] = set()
page = 0
done = False
for page in range(MAX_PAGES):
params = {
"sport_ids": "PADEL",
"size": PAGE_SIZE,
"page": page,
}
logger.info("GET page=%d (total so far: %d)", page, len(all_tenants))
while not done and page < MAX_PAGES:
batch_end = min(page + batch_size, MAX_PAGES)
pages_to_fetch = list(range(page, batch_end))
if next_proxy and len(pages_to_fetch) > 1:
logger.info(
"Fetching pages %d-%d in parallel (%d workers, total so far: %d)",
page, batch_end - 1, len(pages_to_fetch), len(all_tenants),
)
results = _fetch_pages_parallel(pages_to_fetch, next_proxy)
else:
# Serial: reuse the shared session, throttle between pages
page_num = pages_to_fetch[0]
logger.info("GET page=%d (total so far: %d)", page_num, len(all_tenants))
params = {"sport_ids": "PADEL", "size": PAGE_SIZE, "page": page_num}
resp = session.get(PLAYTOMIC_TENANTS_URL, params=params, timeout=HTTP_TIMEOUT_SECONDS)
resp.raise_for_status()
tenants = resp.json()
assert isinstance(tenants, list), (
f"Expected list from Playtomic API, got {type(tenants)}"
)
results = [(page_num, tenants)]
# Process pages in order so the done-detection on < PAGE_SIZE is deterministic
for p, tenants in sorted(results):
new_count = 0
for tenant in tenants:
tid = tenant.get("tenant_id") or tenant.get("id")
@@ -75,13 +126,16 @@ def extract(
new_count += 1
logger.info(
"page=%d got=%d new=%d total=%d", page, len(tenants), new_count, len(all_tenants)
"page=%d got=%d new=%d total=%d", p, len(tenants), new_count, len(all_tenants),
)
# Last page — fewer than PAGE_SIZE results means we've exhausted the list
if len(tenants) < PAGE_SIZE:
done = True
break
page = batch_end
if not next_proxy:
time.sleep(THROTTLE_SECONDS)
payload = json.dumps({"tenants": all_tenants, "count": len(all_tenants)}).encode()