utils_devops 0.1.139__py3-none-any.whl → 0.1.141__py3-none-any.whl

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.
@@ -767,75 +767,69 @@ def check_service_health(compose_file: str, service: str,
767
767
  logger.error(f"Error checking health for {service}: {e}")
768
768
  return {"healthy": False, "error": str(e)}
769
769
 
770
- def wait_for_healthy(compose_file: str, services: Optional[List[str]] = None,
771
- timeout: int = 300, interval: int = 5, logger: Optional[Logger] = None,env_file: Optional[str] = None) -> bool:
772
- """Wait for services to become healthy - ENHANCED LOGGING VERSION"""
773
- # Use parent function's logger if provided, otherwise get default
774
- logger = logger or DEFAULT_LOGGER
775
-
770
+ import time
771
+ from collections import defaultdict
772
+
773
+ def wait_for_healthy(
774
+ compose_file: str,
775
+ services: List[str],
776
+ timeout: int,
777
+ interval: int,
778
+ logger: logger,
779
+ env_file: Optional[str] = None
780
+ ) -> bool:
781
+ """Wait for services to become healthy with detailed status logging."""
776
782
  start_time = time.time()
777
- services_to_check = services or get_services_from_compose(compose_file , env_file)
778
-
779
- logger.info(f"🩺 Starting health checks for {len(services_to_check)} services: {services_to_check}")
780
- logger.info(f"⏰ Timeout: {timeout}s, Check interval: {interval}s")
783
+ attempt = 1
781
784
 
782
- attempt = 0
783
785
  while time.time() - start_time < timeout:
784
- attempt += 1
785
786
  elapsed = time.time() - start_time
786
- time_remaining = timeout - elapsed
787
-
788
- all_healthy = True
789
- unhealthy_services = []
790
- healthy_services = []
791
-
792
- # Check each service
793
- for service in services_to_check:
794
- health_result = check_service_health(compose_file, service)
795
- is_healthy = health_result.get('healthy', False)
796
-
797
- if is_healthy:
798
- healthy_services.append(service)
787
+ remaining = timeout - elapsed
788
+ logger.info(f"🔍 Health check attempt {attempt} ({elapsed:.1f}s elapsed, {remaining:.1f}s remaining):")
789
+
790
+ # Get detailed health status
791
+ detailed_health = _get_detailed_health_status(compose_file, services, logger)
792
+
793
+ # Group services by overall_status
794
+ status_groups = defaultdict(list)
795
+ for service, status in detailed_health.items():
796
+ overall = status['overall_status']
797
+ if overall == 'healthy':
798
+ status_groups[overall].append(service)
799
799
  else:
800
- all_healthy = False
801
- unhealthy_services.append({
802
- 'service': service,
803
- 'status': health_result.get('status', 'unknown'),
804
- 'error': health_result.get('error', 'No error details')
805
- })
806
-
807
- # Log detailed status for each attempt
808
- logger.info(f"🔍 Health check attempt {attempt} ({elapsed:.1f}s elapsed, {time_remaining:.1f}s remaining):")
809
- logger.info(f" ✅ Healthy ({len(healthy_services)}): {healthy_services}")
800
+ detail = f"{service}: {status['status']} | Error: {status['error']}"
801
+ status_groups[overall].append(detail)
802
+
803
+ # Define order and emojis
804
+ statuses = ['healthy', 'starting', 'restarting', 'unhealthy', 'not found']
805
+ emojis = {'healthy': '✅', 'starting': '🚀', 'restarting': '🔄', 'unhealthy': '❌', 'not found': '❓'}
806
+
807
+ # Log groups if they have items
808
+ for status in statuses:
809
+ group = status_groups[status]
810
+ if group:
811
+ emoji = emojis[status]
812
+ logger.info(f" {emoji} {status.capitalize()} ({len(group)}):")
813
+ if status == 'healthy':
814
+ logger.info(f" {sorted(group)}")
815
+ else:
816
+ for detail in sorted(group):
817
+ logger.info(f" - {detail}")
810
818
 
811
- if unhealthy_services:
812
- logger.info(f" ❌ Unhealthy ({len(unhealthy_services)}):")
813
- for us in unhealthy_services:
814
- logger.info(f" - {us['service']}: {us['status']} | Error: {us['error']}")
819
+ # Check if all healthy using the 'healthy' bool
820
+ all_healthy = all(status.get('healthy', False) for status in detailed_health.values())
815
821
 
816
822
  if all_healthy:
817
- total_time = time.time() - start_time
818
- logger.info(f"🎉 ALL SERVICES HEALTHY! Completed in {total_time:.1f}s after {attempt} attempts")
823
+ logger.info(f"🎉 ALL SERVICES HEALTHY! Completed in {elapsed:.1f}s after {attempt} attempts")
819
824
  return True
820
825
 
821
- # Wait before next check
822
- if time_remaining > interval:
823
- logger.info(f"⏳ Waiting {interval}s before next health check...")
824
- dt_ops.time.sleep(interval)
825
- else:
826
- # Don't sleep if we're about to timeout
827
- break
828
-
829
- # Timeout reached
830
- elapsed = time.time() - start_time
831
- logger.error(f"⏰ HEALTH CHECK TIMEOUT after {elapsed:.1f}s and {attempt} attempts!")
832
- logger.error(f"💔 Final status - Healthy: {len(healthy_services)}, Unhealthy: {len(unhealthy_services)}")
833
-
834
- if unhealthy_services:
835
- logger.error("📋 Unhealthy services details:")
836
- for us in unhealthy_services:
837
- logger.error(f" - {us['service']}: {us['status']} | {us['error']}")
826
+ # Wait for next attempt
827
+ logger.info(f"⏳ Waiting {interval}s before next health check...")
828
+ time.sleep(interval)
829
+ attempt += 1
838
830
 
831
+ # Timeout
832
+ logger.error(f"❌ Health check timeout after {time.time() - start_time:.1f}s")
839
833
  return False
840
834
 
841
835
  def health_check_docker_compose(compose_file: str) -> bool:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: utils_devops
3
- Version: 0.1.139
3
+ Version: 0.1.141
4
4
  Summary: Lightweight DevOps utilities for automation scripts: config editing (YAML/JSON/INI/.env), templating, diffing, and CLI tools
5
5
  License: MIT
6
6
  Keywords: devops,automation,nginx,cli,jinja2,yaml,config,diff,templating,logging,docker,compose,file-ops
@@ -9,7 +9,7 @@ utils_devops/core/strings.py,sha256=8s0GSjcyTKwLjJjsJ_XfOJxPtyb549icDlU9SUxSvHI,
9
9
  utils_devops/core/systems.py,sha256=wNbEFUAvbMPdqWN-iXvTzvj5iE9xaWfjZYYvD0EZAH0,47577
10
10
  utils_devops/extras/__init__.py,sha256=ZXHeVLHO3_qiW9AY-UQ_YA9cQzmkLGv54a2UbyvtlM0,3571
11
11
  utils_devops/extras/aws_ops.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- utils_devops/extras/docker_ops.py,sha256=bU5Aadj2nUNSMzx-FVkUa5M7y9e3_ACk8orZ2Fs7Ej4,178584
12
+ utils_devops/extras/docker_ops.py,sha256=oIGLZYSb5V3Kf3DropENITjwL-KpO39XoskhABN3Vls,178011
13
13
  utils_devops/extras/git_ops.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  utils_devops/extras/interaction_ops.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
15
  utils_devops/extras/metrics_ops.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -19,7 +19,7 @@ utils_devops/extras/notification_ops.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
19
19
  utils_devops/extras/performance_ops.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  utils_devops/extras/ssh_ops.py,sha256=8I_AF0q76CJOK2qp68w1oro2SVOZ_v7b8OvgDYcE4tg,73741
21
21
  utils_devops/extras/vault_ops.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
- utils_devops-0.1.139.dist-info/METADATA,sha256=YTI5WKL6D87hI6db6ZyduaZeA8ddCgVjLCjJ2-8Q0pU,1903
23
- utils_devops-0.1.139.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
24
- utils_devops-0.1.139.dist-info/entry_points.txt,sha256=ei3B6ZL5yu6dOq-U1r8wsBdkXeg63RAyV7m8_ADaE6k,53
25
- utils_devops-0.1.139.dist-info/RECORD,,
22
+ utils_devops-0.1.141.dist-info/METADATA,sha256=67hrO8lhrZPtEVWGB-TpuKVASqTaD4vGRC9HJtES9-U,1903
23
+ utils_devops-0.1.141.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
24
+ utils_devops-0.1.141.dist-info/entry_points.txt,sha256=ei3B6ZL5yu6dOq-U1r8wsBdkXeg63RAyV7m8_ADaE6k,53
25
+ utils_devops-0.1.141.dist-info/RECORD,,