1

I'm trying to call function right after command python manage.py runserver it can be simple print. I read some stuff and I find quite interesting topics about def ready(self) like this one Overriding AppConfig.ready() or Execute code when Django starts ONCE only? I follow the instructions but for django 2.1.3 version it doesn't work. One time ready function just isn't called another time I get bunch of AppRegistryNotReady exceptions. I think that call function after server start is quite common thing. It shoulnd't give so much trouble but still I don't find proper solution

UPDATE

I tried another solution

I create middleware class like this one:

import time


class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        while True:
            print("true")
            time.sleep(5)

    def __call__(self, request):

        response = self.get_response(request)

        return response

Now I get proper output like :

Performing system checks...

System check identified no issues (0 silenced).
January 03, 2019 - 14:10:55
Django version 2.1.3, using settings 'CMS.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
true
true
true
true
true
true
true
.
.
.

BUT no connectionenter image description here

KyluAce
  • 933
  • 1
  • 8
  • 25
  • You were pretty clear, but I'm just making sure: you want the function call to occur when the server is ready to get requests, not right after it gets its own call to start? – Charles Landau Jan 02 '19 at 13:29
  • @CharlesLandau Yea when the server is ready I want to call function – KyluAce Jan 02 '19 at 13:35
  • you have to understand that "after server starts" is a rather ambiguous definition. If you're using a multi-processing setup - which is the most common case in production -, you will have one "server start" per process. If the processes are managed by the frontend server (which, once again, is the most common case), then the front might launch new django processes at just any time. And let's not talk about having two or more front servers behind a load balancer - what is the definition of a "server start" here ? – bruno desthuilliers Jan 02 '19 at 14:07
  • @CharlesLandau I updated question – KyluAce Jan 03 '19 at 13:18
  • @brunodesthuilliers I updated question – KyluAce Jan 03 '19 at 13:19
  • @KyluAce what to do you expect with this endless loop ? Of course your browser times out, the middleware blocks the whole server process forever. And I really wonder how you hope to address the "server starts" issue with this actually. What about explaining _exactly_ what you're trying to do AND WHY instead ? I strongly suspect a XY problem here (https://en.wikipedia.org/wiki/XY_problem) – bruno desthuilliers Jan 03 '19 at 13:32
  • @brunodesthuilliers so there is no chance to call all the time working in background method during server working (which starts with server) ? When I for example run this same function but later by view (click button and function starts) all works like charm – KyluAce Jan 03 '19 at 13:37
  • @KyluAce PLEASE explain your REAL problem - the one you're trying to solve by "calling a function right after server startup" - instead. For the moment this is all just a waste of everyone's time. – bruno desthuilliers Jan 03 '19 at 13:43
  • @brunodesthuilliers First of all I have function that should work in background all the time That function checks some values from database etc. This function should work all the time, I mean I don't need to visit website to do something. So if I don't need to visit website this function must be call as fast as this is possible so it should start right after when I run `python manage.py runserver x.x.x.x:yyyy` command. Can't write it in an easier way – KyluAce Jan 03 '19 at 13:58
  • Use a dedicated process for this - it has nothing to do within the django server process. Common solutions are cronjobs and async task queues (ie celery) – bruno desthuilliers Jan 03 '19 at 14:22
  • Also, since you mention `runserver` : you are aware that you must NOT use the dev server in production, are you ? – bruno desthuilliers Jan 03 '19 at 14:46
  • @brunodesthuilliers I know that this is another subject but maybe you could point me a direction, what should I do if I need to create production version but it should be hosted locally – KyluAce Jan 04 '19 at 07:25
  • What's wrong with the doc ? https://docs.djangoproject.com/en/2.1/howto/deployment/ – bruno desthuilliers Jan 04 '19 at 08:12
  • https://stackoverflow.com/questions/6791911/execute-code-when-django-starts-once-only – Josh Feb 18 '19 at 18:04

3 Answers3

2

Edit:

I am still unsure what you are trying to achieve and there are some important concerns commenters have highlighted. Firstly, the AppRegistryNotReady: Apps aren't loaded yet error is really frustrating, I appreciate that. I am not sure how you have organised your project so can't provide an exact solution. It might be the way in which you have organised your files and from where you are importing your app's AppConfig class. Have you put it or any custom functions or classes in your app package level __init__.py, so that you import from there? If so this seems to confuse Django, see https://stackoverflow.com/a/34136825/2275482

Secondly:

I'm trying to call function right after command python manage.py runserver

I think we are are struggling to understand what you are trying to achieve and whether or not you are conflating when your Django app starts with when the server starts. The web server is totally independent of Django as commenters have pointed out; it is a separate process.

Even the test server bundled with Django is independent of your Django app. It is just a simple development server put there for convenience but it isn't required and should not be used in production. Django is built in compliance with PEP 333. It will work, AFAIK, with any WSGI web server compliant with PEP 333, whether that is Apache and mod_wsgi, gunicorn or uWSGI etc etc. If you want code to be execute in relation to the server you are using you need to look into that server documentation.

manage.py like django-admin is just a utility to help with development see https://docs.djangoproject.com/en/2.1/ref/django-admin/. When you call manage.py runserver you are invoking a utility which loads your application and setups a test server. You can see the flow of execution, what utilities it is importing and so on in the file itself. This execution flow is not the same as what would happen when using a production server.

A production server, as far as I know, loads your django app from the root wsgi.py file. It won't even look at manage.py

So this goes back to are you trying to post a message after your server starts, In which case this is independent of Django or, when your Django app starts?

If you are trying to print things after django app starts, is initiated and loaded into the server, then you have a number of options. If you really wanted to, you could edit and add to manage.py but I wouldn't tamper with Django's core beyond that. This will be totally ignored when using a different production server.

If you want to edit the entry point which will be loaded regardless of the server being used then you can edit the project's wsgi.py module or the individual app AppConfig ready() method.

If you want to build something independent of Django which continuously runs in then background then as @bruno-desthuilliers has pointed out, you need to build a separate process either as a cron job or using celery or even django-carrot if you wanted to, although the latter is still linked to the app starting but can work as a separate worker (I think). Django-carrot only has very simple features for small jobs..

I am sorry if this isn't of any help, best I can do with info provided.


I faced a similar issue when I wanted something to run inside the ready() method of my apps AppConfig. For me it was the way in which my app was installed in my INSTALLED_APPS setting variable.

Normally you would register your apps like so:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'my_app',
]

However this will load the base AppConfig class for registering your apps. If you customise and override the app's AppConfig, so that you can declare your own ready() method, which will be executed once the app has been instantiated, you need to refer to the overridden AppConfig directly in the INSTALLED_APPS

So

INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'my_app.apps.MyAPPConfig', # MyAppConfig is the config class that inherits from AppConfig
    ]

Alternatively, if you do not want this do this when a specific app is loaded via it's AppConfig, so not through the ready() method, but rather literally when the project loads into the server you can place a in your project wsgi.py module after the app loads

i.e

application = get_wsgi_application()
print('Hello World')

Hope that helps

alfandango
  • 111
  • 1
  • 6
  • cf my comment on the question - what if you're running a multiprocess server ? – bruno desthuilliers Jan 02 '19 at 14:09
  • The question is to run a function when `manage.py runserver` has finished loading which is a test server and not for production. OP hasn't made it clear if this function is just for testing or for production. I'm interpreting this as after the app starts, as you say `server start` is somewhat ambiguous. – alfandango Jan 02 '19 at 14:14
  • First of all your answer is same like this ones from topic I gave. When I tried that solution with simple print inside `ready()`I get on output 2x print and after that "Performing system checks..." first of all this should be the opposite way first "Preforming system checks..." then print. Anyway when I'm using my final function which will run all the time I get `AppRegistryNotReady: Apps aren't loaded yet` – KyluAce Jan 03 '19 at 07:32
  • @KyluAce I've updated my answer but I am sorry I don't fully understand what you are trying to do. It is the best answer I can give, sorry if it is not much help. – alfandango Jan 03 '19 at 19:07
0

You can just add the function call toward the end of manage.py, in one of your supporting files like routes.py, and so on. But! You indicated that you want the function to be called when the server is ready to receive requests.

Overriding AppConfig.ready() is intended for when you are subclassing AppConfig and adding that to your app registry. It's not clear from your question that you followed that part. You can double-check that you're following the instructions here to ensure you've done that properly.

Charles Landau
  • 4,187
  • 1
  • 8
  • 24
  • 1
    For now I'm pretty sure that I can't use `AppConfig.ready()` with my function, so I tried call function at the end of `manage.py` (I don't have routes.py file in my project) but I get `AppRegistryNotReady: Apps aren't loaded yet.` – KyluAce Jan 03 '19 at 09:06
  • You can't use AppConfig.ready(), you should be trying to use SubclassOfAppConfig.ready() – Charles Landau Jan 03 '19 at 16:43
0

My solution is a bit different and I am open to suggestions from all. The inspiration is from @alfandango's answer to use wsgi.py to run the custom code one time and some other references similar to the current question pointing that putting the code in urls.py will execute the code once but only when the first hit to any URL occurs. Do note that the solution is only helpful/suggested IF:

  1. You want to run database commands/access database when system first runs
  2. You have just one worker. The code will run for more than one worker also but it will be invoked once for each worker
  3. You are okay to delay execution of your code by 1 second(or less) as you will see.

Solution: STEP1: Add the below code to root urls.py :

#normal URL.py invocation
urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^somepaths/', include((some_url, 'some_url'), namespace="some_urls")),
]

#define or import your function
def run_after_system_start():
    pass

#now run the functions
run_after_system_start()

STEP2: In wsgi.py run wget to invoke url.py #regular code for wsgi.py import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'applications.settings')

import os
application = get_wsgi_application()


#below code hits itself(http://0.0.0.0) at some url to just invoke url.py and run the code once. The option for Wget are to enable no output or error is printed. It retries only once with a timeout of 1 second. Also the HIT type is of HTTP POST

try:
    os.system('wget -T 1 -q -o /dev/null -O "/dev/null" --tries=1 --post-data "" http://0.0.0.0/someurl')
except Exception as e:
    pass

Other References:

  1. Wget No error message/output
Pranaysharma
  • 537
  • 6
  • 13