import os
import time
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import docker
import json
import configparser
class FileChangeHandler(FileSystemEventHandler):
def on_modified(self, event):
if event.is_directory:
return
print(f"File {event.src_path} has changed. Restarting containers.")
# Opening JSON file
try:
with open('./vitalengine-router/config_updates/app-config-updates.json', 'r') as jsonfile:
content = jsonfile.read()
print("JSON Content:", content)
json_object = json.loads(content)
except Exception as e:
print(f"Error loading JSON file: {e}")
jsonfile.close()
restart_containers(json_object)
def update_config(config_obj, key, new_val):
for each_section in config_obj.sections():
for (each_key, each_val) in config_obj.items(each_section):
if key == each_key:
print("Matched key, update to config file")
config_obj.set(each_section, each_key, new_val)
return config_obj
def restart_containers(json_object):
skippable_container_list = ["router-mysql", "router-rabbitmq", "dicom-router-rabbitmq", "stage- mysql-db", "stage-redis", "sonarqube"]
# Create a Docker client
client = docker.from_env()
# Get a list of all containers (including stopped ones)
containers = client.containers.list(all=True)
# Iterate through running containers and retrieve statistics
for container in containers:
container_name = container.name
if container_name not in skippable_container_list:
if "ve-config-test" == container_name:
if container.status == 'running':
print(f"Container {container_name} is currently running. Waiting for it to stop...")
# Wait for the container to stop
container.wait()
print(f"Container {container_name} is now stopped. Proceeding to update configuration and restart...")
# Read INI file
config_obj = configparser.ConfigParser()
config_obj.read("./vitalengine-router/ve-config-test/ve_config_test.ini")
# Loop over key-value in JSON file and update config
for k, v in json_object.items():
print(f"Key: {k}")
print(f"Value: {v}")
config_obj = update_config(config_obj, k, v)
# Write the configuration file to 'example.ini'
with open('./vitalengine-router/ve-config-test/ve_config_test.ini', 'w') as configfile:
config_obj.write(configfile)
print(f"Starting container: {container_name}")
container.start()
if __name__ == "__main__":
path_to_watch = "./vitalengine-router/config_updates"
event_handler = FileChangeHandler()
observer = Observer()
observer.schedule(event_handler, path=path_to_watch, recursive=True)
observer.start()
try:
print(f"Watching for changes in {path_to_watch}")
while True:
time.sleep(1)
except KeyboardInterrupt:
observer.stop()
observer.join()
/* ->所以上面是我的一个python脚本,它位于vitalengine-router内部,config_updates也是vitalengine-router内部的一个文件,app-config-update.json位于config_updates内部。而ve-config-test是一个容器,其中包含文件 ve_config_test.ini。 ->所以如果 path_to_watch = "./vitalengine-router/config_updates" 意味着 app-config-update.json 文件发生任何更改,我的代码应该在 ve_config_test.ini 中更改并重新启动容器一次。 ->这意味着如果容器空闲并且我在 app-config-update.json 文件中进行更改,看门狗将触发 onModified 函数并在 ve_config_test.ini 中进行更改,如果容器正在运行,它将等待它完成任务,然后在 ve_config_test.ini 中进行修改并重新启动容器一次。 ->但我的问题是,在 ve_config_test.ini 中修改后,它会重新启动容器两次。
->我希望 ve-config-test 容器在 ve_config_test.ini 更改后仅重新启动一次。 */
我认为您的脚本可能会两次遇到文件修改事件。这是像 watchdog 这样的文件系统监视程序的常见问题。发生这种情况的原因是某些操作系统和编辑器保存文件的方式 - 它们可能会多次写入文件,或者写入临时文件,然后将其重命名为原始文件名,从而导致多个事件。
为了缓解此问题,以下是一些解决方案的高级描述:
实施去抖机制,确保您只对给定时间范围内的第一个事件采取行动。这意味着如果短时间内发生多个文件修改事件,您会将它们视为一个事件。
在重新启动容器之前,检查
ve_config_test.ini
文件的内容是否确实与之前的内容发生了变化。如果没有变化,就不要重启容器。
使用标志或时间戳来标记您正在处理事件以及该过程何时完成。如果您仍在处理前一个事件时出现新事件,您可以选择忽略它或将其排队以在当前事件完成后进行处理。
有关Docker重启策略的更多详细信息,您可以参考以下链接:
更新:
我认为即使在实现了去抖机制之后,容器重新启动两次的问题可能是由于与文件修改事件重叠的多个触发器或长时间运行的操作造成的。当容器正在运行并需要几分钟才能停止时,最好实现一个排队系统而不是简单的去抖来处理此用例。
以下是如何修改脚本以实现排队系统的高级描述: