File size: 2,981 Bytes
2a9b3c7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
"""
์ด ํŒŒ์ผ์€ ์ŠคํŠธ๋ฆผ๋ฆฟ ๋Œ€์‹œ๋ณด๋“œ์˜ ์ตœ์ดˆ ๋กœ๋”ฉ ์‹œ๊ฐ„์„ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•œ ์ปค์Šคํ…€ ์บ์‹ฑ ์Šคํฌ๋ฆฝํŠธ์ž…๋‹ˆ๋‹ค.
๋กœ์ปฌ ํŒŒ์ผ ์บ์‹œ๋ฅผ ์šฐ์„ ์ ์œผ๋กœ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๊ตฌ๊ธ€ ์‹œํŠธ์™€ ๋ฐ์ดํ„ฐ๋ฅผ ๋™๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
"""
import os
import time
import pickle
import threading
import streamlit as st

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

def local_first_cache(cache_filename, ttl=3600):
    """
    Stale-While-Revalidate (๋กœ์ปฌ ์šฐ์„  ์ฝ๊ธฐ) ํŒจํ„ด์„ ๊ตฌํ˜„ํ•œ ์ปค์Šคํ…€ ์บ์‹œ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ.
    - ๋กœ์ปฌ์— pickle ์บ์‹œ๊ฐ€ ์žˆ์œผ๋ฉด 0.1์ดˆ ๋งŒ์— ์ฆ‰์‹œ ๋ฐ˜ํ™˜ (๋Œ€์‹œ๋ณด๋“œ ๋กœ๋”ฉ ๋”œ๋ ˆ์ด ์ œ๊ฑฐ)
    - ์บ์‹œ๊ฐ€ ttl๋ณด๋‹ค ์˜ค๋ž˜๋˜์—ˆ์œผ๋ฉด ๊ธฐ์กด ์บ์‹œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ ๋’ค, ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ์—์„œ ๊ตฌ๊ธ€ ์‹œํŠธ๋ฅผ ์กฐํšŒํ•˜์—ฌ ์บ์‹œ๋ฅผ ์—…๋ฐ์ดํŠธํ•จ
    """
    def decorator(func):
        def wrapper(*args, **kwargs):
            cache_path = os.path.join(BASE_DIR, "scratch", cache_filename)
            
            # 1. ๋กœ์ปฌ ์บ์‹œ๊ฐ€ ์กด์žฌํ•˜๋ฉด ์ตœ์šฐ์„ ์œผ๋กœ ์ฝ์–ด์˜ด
            if os.path.exists(cache_path):
                try:
                    with open(cache_path, "rb") as f:
                        data = pickle.load(f)
                    
                    # 2. ์บ์‹œ๊ฐ€ ๋งŒ๋ฃŒ(ttl ๊ฒฝ๊ณผ)๋˜์—ˆ๋‹ค๋ฉด, ํ™”๋ฉด์—๋Š” ๊ธฐ์กด ๋ฐ์ดํ„ฐ๋ฅผ ๋จผ์ € ๋ฟŒ๋ฆฌ๊ณ  ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์กฐ์šฉํžˆ ์—…๋ฐ์ดํŠธ
                    if time.time() - os.path.getmtime(cache_path) > ttl:
                        def _update_cache():
                            try:
                                res = func(*args, **kwargs)
                                os.makedirs(os.path.dirname(cache_path), exist_ok=True)
                                with open(cache_path, "wb") as f:
                                    pickle.dump(res, f)
                            except Exception as e:
                                print(f"[๊ฒฝ๊ณ ] ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์บ์‹œ ์—…๋ฐ์ดํŠธ ์‹คํŒจ ({cache_filename}): {e}")
                                
                        threading.Thread(target=_update_cache, daemon=True).start()
                    
                    return data
                except Exception as e:
                    print(f"[๊ฒฝ๊ณ ] ๋กœ์ปฌ ์บ์‹œ ์ฝ๊ธฐ ์‹คํŒจ ({cache_filename}), ๋™๊ธฐ์‹์œผ๋กœ ์žฌ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค: {e}")
            
            # 3. ๋กœ์ปฌ ์บ์‹œ๊ฐ€ ์•„์˜ˆ ์—†๋Š” ๊ฒฝ์šฐ (์„œ๋ฒ„ ์ƒ์•  ์ตœ์ดˆ 1ํšŒ) -> ๋™๊ธฐ์‹์œผ๋กœ ๋กœ๋“œํ•˜๊ณ  ์บ์‹œ ์ €์žฅ
            print(f"[์‹œ์ž‘] ์ตœ์ดˆ ๋ฐ์ดํ„ฐ ๋กœ๋“œ ์ค‘... ({cache_filename})")
            res = func(*args, **kwargs)
            try:
                os.makedirs(os.path.dirname(cache_path), exist_ok=True)
                with open(cache_path, "wb") as f:
                    pickle.dump(res, f)
            except Exception as e:
                print(f"[๊ฒฝ๊ณ ] ๋กœ์ปฌ ์บ์‹œ ์ €์žฅ ์‹คํŒจ ({cache_filename}): {e}")
                
            return res
        return wrapper
    return decorator