#Update:
Changing the task from shared_task to app.celeryd.celery.task solves the issue. Is there some additional setup for shared_tasks to work properly?
Completely rewritten still the same error. I'll try to keep it relatively short. The new project structure is a bit cleaner and looks as follows:
proj
|-- app
| |-- controller
| | |-- __init__.py
| | +-- greeting_model.py
| |-- model
| | |-- __init__.py
| | +-- dto
| | |-- __init__.py
| | +-- greeting_dto.py
| |-- service
| | |-- __init__.py
| | +-- greeting_service.py
| |-- tasks
| | |-- __init__.py
| | +-- greeting_tasks.py
| |-- __init__.py
| |-- celeryd.py
| +-- flaskd.py
|-- test.py
|-- worker.py
+-- ws.py
I'm initializing celery and flask separately and provide worker.py which shall be run on client machines, while ws.py (the flask web service) will run on another. Celery initialization is plain simple, and uses rpc backend with RabbitMQ broker. The 2 queues for now are static but later those will be populated from configuration.
from kombu import Queue
from celery import Celery
celery = Celery('LdapProvider',
broker='amqp://admin:passwd#localhost:5672/dev1',
backend='rpc',
include=['app.tasks.greeting_tasks'])
celery.conf.task_queues = (
Queue("q1", routing_key="c1.q1"),
Queue("q2", routing_key="c2.q2"),
)
Worker.py (used to launch celery worker - overly simplified for this question):
from app.celeryd import celery as celery
from celery.bin.worker import worker
if __name__ == '__main__':
celeryd = worker(app=celery)
options = {
'broker': 'amqp://admin:passwd#localhost:5672/dev1',
'queues': 'q1',
'loglevel': 'info',
'traceback': True
}
celeryd.run(**options)
I'll omit flask initialization and jump to greeting_service.py which calls the celery task:
# greeting_service.py:
from app.celeryd import celery
from app.tasks.greeting_tasks import say_hello
class GreetingService(object):
def say_hello(self, name: str) -> str:
async_result = say_hello.apply_async((name,), queue='q1')
return async_result.get()
# greeting_tasks.py
from celery import shared_task
#shared_task(bind=True)
def say_hello(self, name: str) -> str:
return name.capitalize()
This call fails through flask whatever I try. I created test.py just to test if celery works at all:
from app.celeryd import celery
from app.tasks.greeting_tasks import say_hello
if __name__ == '__main__':
async_result = say_hello.apply_async(('jackie',), queue='q1')
print(async_result.get())
Pretty much the same as greeting_service.py it's just not called from greeting_controller which is a flask_restplus namespace. The difference that test.py results in:
/home/pupsz/PycharmProjects/provider/venv37/bin/python /home/pupsz/PycharmProjects/provider/test.py
Jackie
Process finished with exit code 0
[2020-01-16 18:56:17,065: INFO/MainProcess] Received task: app.tasks.greeting_tasks.say_hello[bb45e271-563e-405b-8529-7335a3810976]
[2020-01-16 18:56:17,076: INFO/ForkPoolWorker-2] Task app.tasks.greeting_tasks.say_hello[bb45e271-563e-405b-8529-7335a3810976] succeeded in 0.010257695998006966s: 'Jackie'
while through flask all I get is the already shown and the worker log does not show any incoming task meaning through flask apply_async is not sending the task to RabbitMQ:
File "/home/xyz/PycharmProjects/proj/app/service/greeting_service.py", line 8, in say_hello
return async_result.get()
NotImplementedError: No result backend is configured.
Please see the documentation for more information.
I found one similar problem with django without an answer so I'm kind of stuck and would appreciate some kind of guidance.
Solution: The solution to have the shared_task work as expected was answered here: LINK
Modifying celerz initization as:
from kombu import Queue
from celery import Celery
celery = Celery('LdapProvider',
broker='amqp://admin:passwd#localhost:5672/dev1',
backend='rpc')
# include=['app.tasks.greeting_tasks'])
celery.conf.task_queues = (
Queue("q1", routing_key="c1.q1"),
Queue("q2", routing_key="c2.q2"),
)
celery.set_default()
Even if I were to remove the commented out include line the worker successfully picks up the shared_task defined in app.tasks.greeting_tasks:
[tasks]
. app.tasks.greeting_tasks.say_hello
After the app was set to default_app() no more NotImplementedError was thrown even when using shared_task. As for the reason... I have no idea, it was 6 hours of trial and error of different configs and googling. I find the official documentation lackluster in certain more complex situations.
Related
There is an option in the menifest file to call method during module installation. We can mention pre_init and post_init.
I would like to call one method while upgrading the module as similar to pre_init. because after module gets installed pre_init will not be called.
Any suggestion for this ?
Why I need this ...
I have a stored procedure to generate report data quickly which uses postgresql stored procedure, now when there is a slight change in the procedure I would like to update it thourh the module upgrade process.
There should be some option available to call method during upgrade module as like pre_init and post_init.
I tried following methods to do this.
# Added following code in XML file
<function model="sale.order" name="action_custom_method"/>
#api.model
def action_custom_method(self):
# stored procedure code
return True
But this is not working for me, I am Using odoo 14.
in Odoo 14 it became pre_init_hook & post_init_hook. which would be set in the __manifest__.py
{
'pre_init_hook': pre_init_hook_method,
'post_init_hook': post_init_hook_method,
}
you also add the method definition in __init__.py
def pre_init_hook_method(cr):
env = api.Environment(cr, SUPERUSER_ID, {}) # to get env
def post_init_hook_method(cr, registry):
env = api.Environment(cr, SUPERUSER_ID, {}) # to get env
you may also use the migrations folder & module versioning like what is mentioned there Data Migration
so in your module folder you would have a migration folder. as the following structure:
<moduledir>
`-- migrations
|-- 1.0
| |-- pre-update_table_x.py
| |-- pre-update_table_y.py
| |-- post-create_plop_records.py
| |-- end-cleanup.py
| `-- README.txt # not processed
|-- 12.0.1.1 # processed only on a 12.0 server
| |-- pre-delete_table_z.py
| `-- post-clean-data.py
|-- 0.0.0
| `-- end-invariants.py # processed on all version update
so if your module defined with version like 12.0.1.1 before. you could increment a number to be like 12.0.1.2 in __manifest__.py. later on in your migration folder you add a new folder 12.0.1.2. where you could add pre- or post- python files. which would include you stored procedure definition. please also note that folder 0.0.0 will always run. if that didn't work it could be something else is wrong.
don't hesitate to let us know if you face any problems.
Finally, I got the solution.
We created one .sql file and into that file we added all our stored procedures and other database objects.
We added that sql file in the __manifest__.py
'data': [
'db_function/get_product_sales_history_data.sql',
'db_function/update_product_sales_history.sql',
],
It will execute these sql files at the time of module installation as well as module upgrade time.
I'm using setup.py to package my project. the structure is like:
foo -
|
|--foo/
| |
| |--first.py
| |--second.py
| |--...
|--README
|--requirements.txt
|--scripts/
| |
| |-script1.sh
| |-script2.py
|--service.py
|--setup.py
If I run the current setup.py, which is in accordance with the suggestions here: What is setup.py?
then in the venv/lib/python3.6/site-packages/foo and venv/lib/python3.6/site-packages/scripts I can see all python classes there. But service.py is absent. My question is how to modify the setup.py to include service.py into packaging such that I can find service.py at venv/lib/python3.6/site-packages/?
Thanks in advance!
For top level modules, such as service.py, to be included in the distributions, setuptools offers the py_modules parameter.
The setuptools documentation does not show it clearly, but it is the same as in (now deprecated) distutils:
https://docs.python.org/3/distutils/setupscript.html#listing-individual-modules
setuptools.setup(
# ...
py_modules=['service'], # no '.py'
)
I have been given a skeleton SBT project to work on. The directory structure is as follows:
|-- build.sbt
|-- project
| |-- build.properties
| |-- plugins.sbt
| |-- project
| `-- target
|-- README.md
`-- src
|-- main
| `-- scala
| `-- com
| `-- app-name
| |-- domain
| |-- exception
| |-- repository
| `-- util
`-- test
`-- scala
`-- Vagrantfile
The instructions are to create an app entry point which should take a single command line argument and run some logic.
I have managed to get a simple "hello world" sbt project working but I'm new to scala/sbt. Where would I place this entry point and how can I accept a command line argument?
The root folder for source files would be src/main/scala.
Parameters are referenced using the args array within your entry point object.
The entry point is any object under that source tree which extends App. Since this is a hello world example and you're just getting started, I'd drop it right into the root of the sources (src/main/scala/MyApp.scala).
Something like this:
object MyApp extends App {
println(args.length match {
case 0 => "You passed in no arguments!"
case 1 => s"You passed in 1 argument, which was ${args(0)}"
case x => s"You passed in $x arguments! They are: ${args.mkString(",")}"
})
}
To run your app, issue the sbt run command in the project root. To run with parameters, do sbt run "arg1".
I am trying to figure out how autoloading function with Zend Framework.
questions:
1 - say I want to add to my application/ folder a folder called x/ containing a class named Foo.php. How do I get it auto-loaded when I do new Foo() from a controller? And then how should I name The class Foo? Is "Foo" alright or should I use the name "Application_X_Foo"?
2 - whats this story with $autoloader->registerNamespace('My_')? I mean where should the classes in the namespace My_ live?
Thanks
1.- For application specific classes you should use Application_Model_Foo as the class name and have it located under "application/models/Foo.php"
2.- If you want to add other namespaces/libraries to your project you could add these under the library/ folder. In the "My_" namespace case you should add it to "library/My" folder.
Here, you can have a look to the directory structure of a basic Zend Framework project:
|-- application
| |-- Bootstrap.php
| |-- configs
| | `-- application.ini
| |-- controllers
| | |-- ErrorController.php
| | `-- IndexController.php
| |-- models
| `-- views
| |-- helpers
| `-- scripts
| |-- error
| | `-- error.phtml
| `-- index
| `-- index.phtml
|-- library
|-- public
| |-- .htaccess
| `-- index.php
`-- tests
|-- application
| `-- bootstrap.php
|-- library
| `-- bootstrap.php
`-- phpunit.xml
By the way i would recomend you to have a look to the Zend Framework Quick Start guide:
http://framework.zend.com/manual/en/learning.quickstart.html
I've installed Zend Studio 7.1.1 that contains 1.9 framework.
For the server side, I use easyphp (very similar to wamp)
When I create the project, I obviously obtain this architecture:
MyProject
|-- application
| |-- Bootstrap.php
| |-- configs
| | `-- application.ini
| |-- controllers
| | |-- ErrorController.php
| | `-- IndexController.php
| |-- models
| `-- views
| |-- helpers
| `-- scripts
| |-- error
| | `-- error.phtml
| `-- index
| `-- index.phtml
|-- library
|-- public
| |-- .htaccess
| `-- index.php
`-- tests
|-- application
| `-- bootstrap.php
|-- library
| `-- bootstrap.php
`-- phpunit.xml
To launch the project, I enter:
http://127.0.0.1/MonProjet/public/index.php
But when I create a new controller (TestController.php) and the associated view (application.views/test/index.phtml) and when I enter:
http://127.0.0.1/MonProjet/public/test
the browser returns the error : object not found (404).
although I activated the mod_rewrite
LoadModule rewrite_module modules/mod_rewrite.so
So, how can I set the routing mechanism to reach the new controllers and their views?
Thank you very much,
regards.
It's been quite a while since the question was asked, but nevertheless maybe somebody is still facing the issue. I had the same problem today and it turned out that in apache configuration in httpd.conf the "AllowOverride" was set to "none" and therefore the .htaccess could not be read. Changing it to "All" solved the problem.
Your index.php file has the Autoloader class call which loads all the controller and models automatically.
Along with that you can also add this code in your BootStrap.php file.
protected function _initAutoload()
{
$modeLoader = new Zend_Application_Module_Autoloader(array
('namespace'=>'Application','basePath'=>APPLICATION_PATH ));
return $modeLoader;
}