简体   繁体   English

重新加载Django网站而没有500个服务器错误?

[英]Reload Django Website Without 500 Server Error?

I have a Django/Gunicorn/Nginx website which I build using an Ansible playbook. 我有一个使用Ansible剧本建立的Django / Gunicorn / Nginx网站。 I'm currently in the process of tagging those tasks in my playbook that need to run whenever I add a new feature or fix a bug and want to reload my Django code. 我目前正在标记剧本中的这些任务,这些任务需要在添加新功能或修复错误并希望重新加载Django代码时运行。 My goal is to be able to push any such changes to production as soon as I've tested them on my staging server without having to take my production server down. 我的目标是能够在暂存服务器上测试完所有此类更改后立即将其推送到生产环境,而不必停机。

My playbook is currently set up so that whenever I want to push changes to production, it will delete the entire website directory and rebuild the Pip virtual environment so that there's no leftover "cruft". 我的剧本目前已设置好,以便每当我要将更改推送到制作中时,它将删除整个网站目录并重建Pip虚拟环境,以使没有多余的内容。 The problem is that when I run the Ansible playbook, I get a momentary 500 server error at the point at which it deletes the website directory. 问题是,当我运行Ansible剧本时,在删除网站目录时出现了500服务器暂时错误。 Then, as soon as the next task that checks out the code from Github runs, the error goes away. 然后,一旦下一个从Github签出代码的任务运行,错误就会消失。 Clearly, whenever I reload my code base, if any user is hitting my website at the moment that task runs, they'll get this 500 error too. 显然,每当我重新加载代码库时,如果有任何用户在任务运行时访问我的网站,他们也会收到此500错误。 I've been thinking that once Gunicorn is started and my Django code is loaded into memory, I can delete and reload my code and restart Gunicorn without any interruption to service. 我一直在思考,一旦启动Gunicorn并将我的Django代码加载到内存中,就可以删除并重新加载我的代码并重新启动Gunicorn,而不会中断服务。 This other Stackover question seems to that should be the case. 这个其他Stackover问题似乎应该是这种情况。 However, my tests indicate otherwise. 但是,我的测试表明并非如此。

When a client browser sends a request to Django, does Django reload all the .pyc files into memory? 当客户端浏览器向Django发送请求时,Django是否会将所有.pyc文件重新加载到内存中? Is that what's causing this problem? 那是什么引起这个问题? Is there any way to prevent this momentary outage when I reload my Django code without removing the task that deletes the old code? 当我重新加载Django代码而不删除删除旧代码的任务时,有什么方法可以防止这种瞬时中断吗?

Here are excerpts from my Ansible playbook: 以下是我的Ansible剧本的摘录:

- name: configure web server
  hosts: webservers
  gather_facts: True
  tasks:
     # This task causes momentary 500 server error
     - name: delete any existing project repo
       file: >
         path={{ repo_path }}
         state=absent
       tags: reload

    - name: check out {{ repo_version }} of Github repo
      git: >
        repo={{ repo_url }}
        version={{ repo_version }}
        dest={{ repo_path }}
        accept_hostkey=yes
      register: checkout
      until: checkout|success
      retries: 5
      delay: 10
      become: true
      become_user: "{{ me }}"
      tags: reload

    # ... more tasks

    - name: install python packages into virtual environment
      pip: >
        requirements={{ repo_path }}/requirements/{{ server_tier }}.txt
        state=present
        virtualenv={{ venvs_path }}/{{ commit_hash }}
      tags: reload

    # ... more tasks

    - name: reload gunicorn
      command: pkill -HUP gunicorn
  become: true
  become_user: root
  tags: reload

Solution : Make your django root directory a symb link. 解决方案: 将django根目录设为symb链接。

Let me explain my solution in details. 让我详细解释我的解决方案。 Make sure that your code root is a symbolic link to actual version of code that is serving the traffic. 确保您的代码根是到服务流量的实际代码版本的符号链接。 During a deployment your ansible script will essentially create a new virtualenv, and install the requirements. 在部署期间,您的ansible脚本将实质上创建一个新的virtualenv,并安装需求。 And pull code in a new directory which should have current timestamp in the name. 并将代码拉入新目录中,该目录中应包含当前时间戳。 And you do whatever you need to do make it ready to serve traffic. 您可以做任何需要做的事情,使其随时为流量提供服务。 Then in the last step you just start pointing the django root directory link to new location. 然后,在最后一步中,您只是开始将Django根目录链接指向新位置。

/home/ubuntu/project/current -> /home/ubuntu/project/releases/145678/
/home/ubuntu/project/releases/123456/
/home/ubuntu/project/releases/134567/
/home/ubuntu/project/releases/145678/

In the above directory structure, you can point current to one of the releases. 在上面的目录结构中,您可以将当前指向这些发行版之一。 With every new deployment you can create a new release and then subsequently point current to new release directory. 对于每个新的部署,您可以创建一个新发行版,然后将当前指向新发行版目录。

After this you can restart your gunicorn to refresh the settings from new codebase. 之后,您可以重新启动您的gunicorn,以从新的代码库刷新设置。

You can have a cron job to remove very old releases from the machine. 您可以执行cron作业,以从计算机中删除非常旧的发行版。

Let me know if you need more clarification. 让我知道是否需要进一步说明。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM