# ๐Ÿ’ก ๊ธฐ๋Šฅ ์ŠคํฌํŠธ๋ผ์ดํŠธ: ์ง€์†์ ์ธ ํ”Œ๋Ÿฌ๊ทธ์ธ ์บ์‹ฑ ## ๐Ÿ’พ ์„ฑ๋Šฅ, ์•ˆ์ •์„ฑ ๋ฐ ๋„คํŠธ์›Œํฌ ํšจ์œจ์„ฑ์„ ์œ„ํ•œ ์บ์‹ฑ ์ด์ œ ์‹œ์Šคํ…œ์€ ์™ธ๋ถ€ ๋„คํŠธ์›Œํฌ ๋ถ€ํ•˜(์˜ˆ: ๋‚ ์”จ, ๋ฒˆ์—ญ API)๋ฅผ ์ค„์ด๊ณ  ์‹คํ–‰์„ ๊ฐ€์†ํ™”ํ•˜๋„๋ก ์„ค๊ณ„๋œ ์ค‘์•™ ์ง‘์ค‘์‹ ์˜๊ตฌ ์บ์‹ฑ ๋ฉ”์ปค๋‹ˆ์ฆ˜(`simple_plugin_cache`)์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์บ์‹œ๋Š” **์ง€์†์ **์ž…๋‹ˆ๋‹ค. ์ฆ‰, ์„œ๋น„์Šค๋ฅผ ๋‹ค์‹œ ์‹œ์ž‘ํ•ด๋„ ํ•ญ๋ชฉ์ด ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. **๋ชฉํ‘œ:** ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ์„ ์ค„์ด๊ณ  API ๋‚จ์šฉ์„ ๋ฐฉ์ง€ํ•˜๋ฉฐ ์™ธ๋ถ€ ์„œ๋น„์Šค ์ค‘๋‹จ ์‹œ ๋น ๋ฅธ ๋Œ€์ฒด ์‘๋‹ต์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. --- ### 1. ๊ธฐ๋ณธ ์บ์‹ฑ ๊ตฌํ˜„(TTL ๊ธฐ๋ฐ˜) ํ•จ์ˆ˜ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œํ•˜๋ ค๋ฉด **ํ™•์ธ**, **์‹คํ–‰**, **์ €์žฅ**์ด๋ผ๋Š” ์„ธ ๊ฐ€์ง€ ๋ธ”๋ก์— ๊ฑธ์ณ ํ•ต์‹ฌ ๋…ผ๋ฆฌ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. #### 1.1 ๊ฐ€์ ธ์˜ค๊ธฐ ๋ฐ ๊ตฌ์„ฑ ํ•„์š”ํ•œ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ํ”Œ๋Ÿฌ๊ทธ์ธ ์Šคํฌ๋ฆฝํŠธ(์˜ˆ: `weather.py`)์— TTL(Time-To-Live) ์ƒ์ˆ˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ```python from scripts.py.func.simple_plugin_cache import get_cached_result, set_cached_result from pathlib import Path # Define the Time-To-Live for successful data WEATHER_TTL = 300 # 5 minutes ``` #### 1.2 `execute` ๋ธ”๋ก์˜ ์บ์‹ฑ ๋กœ์ง '์‹คํ–‰' ํ•จ์ˆ˜๋Š” ๋„คํŠธ์›Œํฌ ํ˜ธ์ถœ์„ ํ•˜๊ธฐ ์ „์— ๋จผ์ € ์บ์‹œ๋œ ๊ฒฐ๊ณผ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ```python def execute(match_data, logger): # ASSUMPTION: BASE_DIR_FOR_CACHE points to a stable, persistent directory (e.g., TMP_DIR) BASE_DIR_FOR_CACHE = Path(...) # The cache key must be a tuple of all arguments that affect the function's result. cache_key_args = (city, lang) # --- BLOCK A: PRIMARY CACHE CHECK (TTL-Driven) --- cached_response = get_cached_result( BASE_DIR_FOR_CACHE, 'plugin_get_weather', # Unique name for this function/operation cache_key_args, WEATHER_TTL, # The TTL for this entry logger=logger ) if cached_response: return cached_response # <-- CACHE HIT: Return immediately # --- BLOCK B: NETWORK EXECUTION (ONLY on Cache Miss) --- try: # Execute your CURL/Requests/External API call here. response = "Successful API response..." # --- SUCCESS: STORE RESULT --- set_cached_result(BASE_DIR_FOR_CACHE, 'plugin_get_weather', cache_key_args, response) return response # --- BLOCK C: EXCEPTION & FAILOVER (Stale Cache Strategy) --- except Exception as e: logger.warning(f"API call failed ({type(e).__name__}). Attempting stale cache fallback...") # SECOND CACHE CHECK: Retrieve the last stored entry, ignoring its age (ttl_seconds=None). stale_response = get_cached_result( BASE_DIR_FOR_CACHE, 'plugin_get_weather', cache_key_args, logger=logger # Important: TTL is explicitly omitted (None) here ) if stale_response: logger.warning("Delivering STALE cache as fallback.") return stale_response # NO FALLBACK AVAILABLE: Return the original error message. # Ensure you handle all specific exceptions as defined in your plugin. if isinstance(e, FileNotFoundError): return "Error: 'curl' program not found." # ... (other exception handlers) ... return f"Error: Could not fetch data and no fallback available. Cause: {e}" ``` --- ### 2. ๊ณ ๊ธ‰ ์บ์‹ฑ ๋ชจ๋“œ #### A. ์˜๊ตฌ(์˜์›ํ•œ) ์บ์‹ฑ ๊ฒฐ๊ณผ๊ฐ€ **๋งŒ๋ฃŒ๋˜์ง€ ์•Š์•„์•ผ** ํ•˜๋Š” ๊ฒฝ์šฐ(์˜ˆ: ์ •์  ๊ตฌ์„ฑ ์กฐํšŒ) `ttl_seconds` ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์™„์ „ํžˆ ์ƒ๋žตํ•˜์„ธ์š”. ```python # The entry will be considered valid forever until manually overwritten. cached_result = get_cached_result(BASE_DIR_FOR_CACHE, 'static_config', ('my_key',), logger=logger) ``` #### B. ์บ์‹œ ํ‚ค(`key_args`) ์š”๊ตฌ ์‚ฌํ•ญ * `key_args`๋Š” ๊ฒฐ๊ณผ๋ฅผ ์ •์˜ํ•˜๋Š” ๋ชจ๋“  ๋ณ€์ˆ˜(์˜ˆ: `(city, ์–ธ์–ด, ๋‹จ์œ„_์‹œ์Šคํ…œ)`)๋ฅผ ํฌํ•จํ•˜๋Š” **ํŠœํ”Œ**์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. * ์บ์‹ฑ ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ **`pathlib.Path`**์™€ ๊ฐ™์€ ์ผ๋ฐ˜์ ์ธ JSON์ด ์•„๋‹Œ ์ง๋ ฌํ™” ๊ฐ€๋Šฅ Python ๊ฐ์ฒด๋ฅผ ํ‚ค ์ƒ์„ฑ์„ ์œ„ํ•œ ๋ฌธ์ž์—ด๋กœ ์ž๋™ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.