# python/02-caching-strategies.py"""Advanced caching strategies for web performance"""fromtypingimportList,Dict,Any,Optional,Union,Callablefromdataclassesimportdataclass,asdictfromenumimportEnumimportasyncioimporttimeimportjsonimporthashlibfromdatetimeimportdatetime,timedeltaimportthreadingfromcollectionsimportOrderedDictclassCacheStrategy(Enum):"""Cache strategy enumeration"""LRU="lru"LFU="lfu"TTL="ttl"WRITE_THROUGH="write_through"WRITE_BACK="write_back"@dataclassclassCacheEntry:"""Cache entry definition"""key:strvalue:Anycreated_at:datetimeaccessed_at:datetimeaccess_count:int=0ttl:Optional[int]=Nonedefis_expired(self)->bool:"""Check if cache entry is expired"""ifself.ttlisNone:returnFalsereturndatetime.utcnow()>self.created_at+timedelta(seconds=self.ttl)defupdate_access(self)->None:"""Update access information"""self.accessed_at=datetime.utcnow()self.access_count+=1classLRUCache:"""LRU cache implementation"""def__init__(self,max_size:int=1000):self.max_size=max_sizeself.cache:OrderedDict[str,CacheEntry]=OrderedDict()self.lock=threading.Lock()defget(self,key:str)->Optional[Any]:"""Get value from cache"""withself.lock:ifkeyinself.cache:entry=self.cache[key]ifentry.is_expired():delself.cache[key]returnNone# Move to end (most recently used)self.cache.move_to_end(key)entry.update_access()returnentry.valuereturnNonedefset(self,key:str,value:Any,ttl:Optional[int]=None)->None:"""Set value in cache"""withself.lock:entry=CacheEntry(key=key,value=value,created_at=datetime.utcnow(),accessed_at=datetime.utcnow(),ttl=ttl)self.cache[key]=entry# Remove oldest if over capacityiflen(self.cache)>self.max_size:self.cache.popitem(last=False)defdelete(self,key:str)->bool:"""Delete key from cache"""withself.lock:ifkeyinself.cache:delself.cache[key]returnTruereturnFalsedefclear(self)->None:"""Clear all cache entries"""withself.lock:self.cache.clear()defget_stats(self)->Dict[str,Any]:"""Get cache statistics"""withself.lock:total_entries=len(self.cache)expired_entries=sum(1forentryinself.cache.values()ifentry.is_expired())return{"total_entries":total_entries,"expired_entries":expired_entries,"active_entries":total_entries-expired_entries,"max_size":self.max_size,"utilization":total_entries/self.max_sizeifself.max_size>0else0}classDistributedCache:"""Distributed cache implementation"""def__init__(self,nodes:List[str]):self.nodes=nodesself.node_count=len(nodes)self.local_cache=LRUCache(max_size=1000)self.consistency_level="eventual"def_get_node(self,key:str)->str:"""Get node for key using consistent hashing"""hash_value=int(hashlib.md5(key.encode()).hexdigest(),16)node_index=hash_value%self.node_countreturnself.nodes[node_index]asyncdefget(self,key:str)->Optional[Any]:"""Get value from distributed cache"""# Try local cache firstlocal_value=self.local_cache.get(key)iflocal_valueisnotNone:returnlocal_value# Try distributed cachenode=self._get_node(key)# In real implementation, this would make HTTP request to nodedistributed_value=awaitself._get_from_node(node,key)ifdistributed_valueisnotNone:# Cache locallyself.local_cache.set(key,distributed_value)returndistributed_valuereturnNoneasyncdefset(self,key:str,value:Any,ttl:Optional[int]=None)->None:"""Set value in distributed cache"""# Set in local cacheself.local_cache.set(key,value,ttl)# Set in distributed cachenode=self._get_node(key)awaitself._set_in_node(node,key,value,ttl)asyncdef_get_from_node(self,node:str,key:str)->Optional[Any]:"""Get value from specific node"""# Simulate network requestawaitasyncio.sleep(0.01)returnNone# Simulate cache missasyncdef_set_in_node(self,node:str,key:str,value:Any,ttl:Optional[int])->None:"""Set value in specific node"""# Simulate network requestawaitasyncio.sleep(0.01)classCacheManager:"""Cache manager for multiple cache strategies"""def__init__(self):self.caches:Dict[str,Union[LRUCache,DistributedCache]]={}self.strategies:Dict[str,CacheStrategy]={}self.default_ttl=3600# 1 hourdefadd_cache(self,name:str,cache:Union[LRUCache,DistributedCache],strategy:CacheStrategy=CacheStrategy.LRU)->None:"""Add cache to manager"""self.caches[name]=cacheself.strategies[name]=strategydefget(self,cache_name:str,key:str)->Optional[Any]:"""Get value from specific cache"""ifcache_namenotinself.caches:returnNonecache=self.caches[cache_name]ifisinstance(cache,LRUCache):returncache.get(key)elifisinstance(cache,DistributedCache):# This would be async in real implementationreturnNonedefset(self,cache_name:str,key:str,value:Any,ttl:Optional[int]=None)->None:"""Set value in specific cache"""ifcache_namenotinself.caches:returncache=self.caches[cache_name]ifisinstance(cache,LRUCache):cache.set(key,value,ttlorself.default_ttl)elifisinstance(cache,DistributedCache):# This would be async in real implementationpassdefinvalidate(self,cache_name:str,key:str)->bool:"""Invalidate key in specific cache"""ifcache_namenotinself.caches:returnFalsecache=self.caches[cache_name]ifisinstance(cache,LRUCache):returncache.delete(key)elifisinstance(cache,DistributedCache):# This would be async in real implementationreturnFalsereturnFalsedefget_all_stats(self)->Dict[str,Dict[str,Any]]:"""Get statistics for all caches"""stats={}forname,cacheinself.caches.items():ifisinstance(cache,LRUCache):stats[name]=cache.get_stats()elifisinstance(cache,DistributedCache):stats[name]={"type":"distributed","nodes":len(cache.nodes)}returnstatsclassCacheDecorator:"""Cache decorator for function results"""def__init__(self,cache_manager:CacheManager,cache_name:str,ttl:Optional[int]=None):self.cache_manager=cache_managerself.cache_name=cache_nameself.ttl=ttldef__call__(self,func:Callable)->Callable:@wraps(func)defwrapper(*args,**kwargs):# Generate cache key from function argumentscache_key=self._generate_cache_key(func.__name__,args,kwargs)# Try to get from cachecached_result=self.cache_manager.get(self.cache_name,cache_key)ifcached_resultisnotNone:returncached_result# Execute functionresult=func(*args,**kwargs)# Cache resultself.cache_manager.set(self.cache_name,cache_key,result,self.ttl)returnresultreturnwrapperdef_generate_cache_key(self,func_name:str,args:tuple,kwargs:dict)->str:"""Generate cache key from function arguments"""key_data={"func_name":func_name,"args":args,"kwargs":sorted(kwargs.items())}key_string=json.dumps(key_data,sort_keys=True)returnhashlib.md5(key_string.encode()).hexdigest()# Usage examplesdefexample_caching_strategies():"""Example caching strategies usage"""# Create cache managercache_manager=CacheManager()# Add LRU cachelru_cache=LRUCache(max_size=100)cache_manager.add_cache("lru",lru_cache,CacheStrategy.LRU)# Add distributed cachedistributed_cache=DistributedCache(["node1","node2","node3"])cache_manager.add_cache("distributed",distributed_cache,CacheStrategy.TTL)# Cache decorator example@CacheDecorator(cache_manager,"lru",ttl=300)defexpensive_calculation(n:int)->int:"""Expensive calculation with caching"""time.sleep(0.1)# Simulate expensive operationreturnn*n# Test cachingstart_time=time.time()result1=expensive_calculation(10)end_time=time.time()print(f"First call: {result1} in {end_time-start_time:.4f}s")start_time=time.time()result2=expensive_calculation(10)end_time=time.time()print(f"Second call: {result2} in {end_time-start_time:.4f}s")# Get cache statsstats=cache_manager.get_all_stats()print(f"Cache stats: {stats}")
# python/03-load-balancing.py"""Load balancing strategies for web performance"""fromtypingimportList,Dict,Any,Optional,Callablefromdataclassesimportdataclass,asdictfromenumimportEnumimportasyncioimporttimeimportrandomimportstatisticsfromdatetimeimportdatetime,timedeltaclassLoadBalancingStrategy(Enum):"""Load balancing strategy enumeration"""ROUND_ROBIN="round_robin"LEAST_CONNECTIONS="least_connections"WEIGHTED_ROUND_ROBIN="weighted_round_robin"LEAST_RESPONSE_TIME="least_response_time"RANDOM="random"@dataclassclassServer:"""Server definition"""server_id:strhost:strport:intweight:int=1max_connections:int=100current_connections:int=0response_time:float=0.0is_healthy:bool=Truelast_health_check:datetime=Nonedefget_utilization(self)->float:"""Get server utilization"""returnself.current_connections/self.max_connectionsifself.max_connections>0else0defupdate_response_time(self,response_time:float)->None:"""Update server response time"""self.response_time=response_timeself.last_health_check=datetime.utcnow()classLoadBalancer:"""Load balancer implementation"""def__init__(self,strategy:LoadBalancingStrategy=LoadBalancingStrategy.ROUND_ROBIN):self.strategy=strategyself.servers:List[Server]=[]self.current_index=0self.server_stats:Dict[str,List[float]]={}self.health_check_interval=30# secondsself.health_check_task=Nonedefadd_server(self,server:Server)->None:"""Add server to load balancer"""self.servers.append(server)self.server_stats[server.server_id]=[]defremove_server(self,server_id:str)->bool:"""Remove server from load balancer"""fori,serverinenumerate(self.servers):ifserver.server_id==server_id:delself.servers[i]ifserver_idinself.server_stats:delself.server_stats[server_id]returnTruereturnFalsedefget_server(self)->Optional[Server]:"""Get server based on load balancing strategy"""healthy_servers=[sforsinself.serversifs.is_healthy]ifnothealthy_servers:returnNoneifself.strategy==LoadBalancingStrategy.ROUND_ROBIN:returnself._round_robin_selection(healthy_servers)elifself.strategy==LoadBalancingStrategy.LEAST_CONNECTIONS:returnself._least_connections_selection(healthy_servers)elifself.strategy==LoadBalancingStrategy.WEIGHTED_ROUND_ROBIN:returnself._weighted_round_robin_selection(healthy_servers)elifself.strategy==LoadBalancingStrategy.LEAST_RESPONSE_TIME:returnself._least_response_time_selection(healthy_servers)elifself.strategy==LoadBalancingStrategy.RANDOM:returnself._random_selection(healthy_servers)else:returnhealthy_servers[0]def_round_robin_selection(self,servers:List[Server])->Server:"""Round robin server selection"""server=servers[self.current_index%len(servers)]self.current_index+=1returnserverdef_least_connections_selection(self,servers:List[Server])->Server:"""Least connections server selection"""returnmin(servers,key=lambdas:s.current_connections)def_weighted_round_robin_selection(self,servers:List[Server])->Server:"""Weighted round robin server selection"""total_weight=sum(server.weightforserverinservers)iftotal_weight==0:returnservers[0]# Simple weighted selectionweights=[server.weightforserverinservers]selected_server=random.choices(servers,weights=weights)[0]returnselected_serverdef_least_response_time_selection(self,servers:List[Server])->Server:"""Least response time server selection"""returnmin(servers,key=lambdas:s.response_time)def_random_selection(self,servers:List[Server])->Server:"""Random server selection"""returnrandom.choice(servers)defrecord_request(self,server:Server,response_time:float)->None:"""Record request statistics"""server.current_connections+=1server.update_response_time(response_time)ifserver.server_idinself.server_stats:self.server_stats[server.server_id].append(response_time)defrecord_response(self,server:Server)->None:"""Record response completion"""server.current_connections=max(0,server.current_connections-1)asyncdefstart_health_monitoring(self)->None:"""Start health monitoring for servers"""whileTrue:forserverinself.servers:awaitself._health_check_server(server)awaitasyncio.sleep(self.health_check_interval)asyncdef_health_check_server(self,server:Server)->None:"""Perform health check on server"""try:# Simulate health checkstart_time=time.time()awaitasyncio.sleep(0.01)# Simulate network requestresponse_time=time.time()-start_timeserver.update_response_time(response_time)server.is_healthy=response_time<1.0# Health thresholdexceptExceptionase:print(f"Health check failed for {server.server_id}: {e}")server.is_healthy=Falsedefget_server_stats(self)->Dict[str,Any]:"""Get load balancer statistics"""healthy_servers=[sforsinself.serversifs.is_healthy]total_connections=sum(s.current_connectionsforsinself.servers)avg_response_time=statistics.mean([s.response_timeforsinhealthy_servers])ifhealthy_serverselse0return{"total_servers":len(self.servers),"healthy_servers":len(healthy_servers),"total_connections":total_connections,"average_response_time":avg_response_time,"strategy":self.strategy.value,"servers":[{"server_id":s.server_id,"host":s.host,"port":s.port,"is_healthy":s.is_healthy,"current_connections":s.current_connections,"response_time":s.response_time,"utilization":s.get_utilization()}forsinself.servers]}classAutoScaling:"""Auto-scaling for load balancer"""def__init__(self,load_balancer:LoadBalancer,min_servers:int=2,max_servers:int=10):self.load_balancer=load_balancerself.min_servers=min_serversself.max_servers=max_serversself.scale_up_threshold=0.8# 80% utilizationself.scale_down_threshold=0.3# 30% utilizationself.scale_cooldown=300# 5 minutesself.last_scale_time=0defshould_scale_up(self)->bool:"""Check if should scale up"""iftime.time()-self.last_scale_time<self.scale_cooldown:returnFalseiflen(self.load_balancer.servers)>=self.max_servers:returnFalse# Check if any server is over thresholdforserverinself.load_balancer.servers:ifserver.get_utilization()>self.scale_up_threshold:returnTruereturnFalsedefshould_scale_down(self)->bool:"""Check if should scale down"""iftime.time()-self.last_scale_time<self.scale_cooldown:returnFalseiflen(self.load_balancer.servers)<=self.min_servers:returnFalse# Check if all servers are under thresholdforserverinself.load_balancer.servers:ifserver.get_utilization()>self.scale_down_threshold:returnFalsereturnTrueasyncdefscale_up(self)->bool:"""Scale up by adding server"""ifnotself.should_scale_up():returnFalse# Create new servernew_server=Server(server_id=f"server_{len(self.load_balancer.servers)+1}",host="localhost",port=8000+len(self.load_balancer.servers),weight=1)self.load_balancer.add_server(new_server)self.last_scale_time=time.time()print(f"Scaled up: Added server {new_server.server_id}")returnTrueasyncdefscale_down(self)->bool:"""Scale down by removing server"""ifnotself.should_scale_down():returnFalse# Remove server with least connectionsifself.load_balancer.servers:server_to_remove=min(self.load_balancer.servers,key=lambdas:s.current_connections)self.load_balancer.remove_server(server_to_remove.server_id)self.last_scale_time=time.time()print(f"Scaled down: Removed server {server_to_remove.server_id}")returnTruereturnFalse# Usage examplesasyncdefexample_load_balancing():"""Example load balancing usage"""# Create load balancerload_balancer=LoadBalancer(LoadBalancingStrategy.ROUND_ROBIN)# Add serversforiinrange(3):server=Server(server_id=f"server_{i+1}",host="localhost",port=8000+i,weight=1)load_balancer.add_server(server)# Create auto-scalingauto_scaling=AutoScaling(load_balancer,min_servers=2,max_servers=5)# Simulate requestsforiinrange(10):server=load_balancer.get_server()ifserver:# Simulate request processingresponse_time=random.uniform(0.1,0.5)load_balancer.record_request(server,response_time)# Simulate response completionawaitasyncio.sleep(0.1)load_balancer.record_response(server)print(f"Request {i+1} handled by {server.server_id}")# Get load balancer statsstats=load_balancer.get_server_stats()print(f"Load balancer stats: {stats}")# Test auto-scalingifauto_scaling.should_scale_up():awaitauto_scaling.scale_up()ifauto_scaling.should_scale_down():awaitauto_scaling.scale_down()