Using gevent.evnet with celery.task - python

I've been working on a long-polling system. I use flask + mongokit + celery + gevent.
When the process in celery task is done, gevent.event.set() doesn't work. I want help to figure it out. (The reason I use gevent at the same time as celery, is because there is a huge process to deal with in Notification system.)
Here is my sample code.
#server.py
#celery.task()
def doing_task(uid, message):
notification = Notification() # this is a notification Model
notification.add(request.args.get('to'), some_notification)
app.event.set()
app.event.clear()
#app.route('/main')
def main():
return render_template('main.html')
#app.route('/set')
def set():
doing_task.delay(request.args.get('uid'), 'Notify')
return 'OK'
#app.route('/poll')
def poll():
uid = request.args.get('uid')
app.event.wait()
if is_authorized(uid): #uid 1 is a authorized account
return Notification().get(uid)
#main.html
<body>
<button>Click me</button>
</body>
<script>
$('button').click(function(e) {
$.ajax({
'url': '/set',
'data': 'uid=1',
'success': function(data) {
console.log(data);
}
});
e.preventDefault();
});
var poll = function() {
return $.ajax({
'url': '/poll',
'method': 'get',
'async':true,
'dataType': 'json',
'timeout': 10000,
'success': function(data) {
console.log(data);
setTimeout(poll, 50);
},
'error':function (req,sta,er){
setTimeout(poll, 3000);
},
});
};
poll()
</script>

Now, in Flask 0.9 Flask.app_context is added, With Flask.app_context you can get a context of current.
See Application Context.
For example,
from flask import Flask
from celery import Celery
app = Flask(__name__)
celery = Celery(__name__)
#celery.task
def hello():
# Also, you are able to deal with current request as use test_request_context
with app.app_context():
print current_app
with app.test_request_context() as request:
print('Hello {0!r}'.format(request))

Related

Is there a way to call a Cloud Function through Cloud Task using form-data?

I have a Cloud Function(Python - Flask) that is expecting to receive a form-data with two files, it works well when I request it directly, but using Cloud Task it's not reaching in there. Here is what I get: ImmutableMultiDict([])
ps: Using Python for the Cloud Function and Node.JS for the Cloud Task.
Tried to Google, and searched over here and have no answers, even the docs don't say anything about it. Any tips?
that's the code that I'm using to call Cloud Task:
const auth = new GoogleAuth({})
const client = new CloudTasksClient({ credentials: credentials });
const formData = new FormData();
formData.append('pdf_file', 'x');
const task = {
httpRequest: {
httpMethod: 'POST',
url,
body: formData,
headers: {
"Content-Type": "multipart/form-data"
},
oidcToken: {
serviceAccountEmail: "x#appspot.gserviceaccount.com"
}
}
}
const request = { parent: parent, task: task, auth: auth }
const [ response ] = await client.createTask(request);
console.log(response);
console.log(`created task ${response.name}`);
that's the code for my Cloud Function, that I'm using as a test:
import functions_framework
#functions_framework.http
def main(request):
if request.method != 'POST':
print('ERROR: its not a post request')
return {'error': 'Invalid method'}, 400
print(request.form)
return 'ok'

Socketio implementation with FastApi and React

I have the following techstack
FastApi - backend
React - frontend
and want to implement socketio(not Websockets provided by FastApi). It lacks documentation in both FastApi and Socketio
As needed we are using python-socketio for backend socket server and on react we will be using socket.io-client.
After installation we need to setup a socket server.
Backend Implementation
# socket.py
def handle_connect(sid, environ):
logger.info(f"Socket connected with sid {sid}")
class SocketManager:
def __init__(self, origins: List[str]):
self.server = socketio.AsyncServer(
cors_allowed_origins=origins,
async_mode="asgi",
logger=True,
engineio_logger=True,
)
self.app = socketio.ASGIApp(self.server)
#property
def on(self):
return self.server.on
#property
def send(self):
return self.server.send
def mount_to(self, path: str, app: ASGIApp):
app.mount(path, self.app)
socket_manager = SocketManager(settings.origins)
socket_manager.on("connect", handler=handle_connect)
Double check your cors origins. Also you can add other handlers as well using socket_manager.on.
#main.py
from socket import
app = FastAPI(...)
socket_manager.mount_to("/ws", app)
Frontend Implementation
Basic code for integration is as simple as
import { io } from "socket.io-client";
const socket = io("ws://localhost:8000", {{ path: "/ws/socket.io/", transports: ['websocket', 'polling'] }});
socket.on("connect", () => { console.log("Connected", socket.id) });
socket.on("response", () => { console.log("Response", socket.id) });
socket.on("message", data => { console.log(data) });
For my project i created a context for this as follows
import React, { createContext, useContext, useEffect, useState } from 'react';
import { io } from "socket.io-client";
import { useToastContext } from './ToastContext';
export const SocketContext = createContext()
export const SocketProvider = ({ children, uri, options }) => {
const [socketIo, setSocketIo] = useState()
const { sendToast } = useToastContext();
useEffect(() => {
const socket = io(uri, options);
socket.on("connect", () => { console.log("Connected", socket.id) });
socket.on("response", () => { console.log("Response", socket.id) });
socket.on("message", data => {
sendToast(data)
});
setSocketIo(socket)
}, [])
return (
<SocketContext.Provider value={socketIo}>
{children}
</SocketContext.Provider>
)
}
export const useSocket = () => {
return useContext(SocketContext)
}
Now to finally send a message from your server to client you can do
socket_manager.send("Hello World")
Points worth noting
CORS origin should be exactly same if it is http://localhost:3000 from frontend then it should be http://localhost:3000 and not http://localhost:3000/. Look for the backslash
Also the socketio documentation says transports: ['websocket', 'polling'] is default but when i remove this. It gives me cors error. Documentation might be out of date.

How to post request to Flask using vue?

I want to post data from Vue to flask
If I don't use parameter data: {},it's no problem.
If I use, error occurs
and this is the server (HTTP Status Code is 200)
Why is this happening? What should I do?
code:
Home.vue
<script>
import axios from 'axios'
export default {
created() {
this.getData();
},
methods: {
getData() {
axios({
baseURL: 'http://127.0.0.1:5001',
url: '/recData',
method: 'post',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
}).then(res=>{
console.log(res);
}).catch(err=>{
console.log(err);
})
}
},
}
</script>
fls_2.py
from flask import Flask, request
from flask_cors import CORS
app = Flask(__name__)
CORS(app, resources={r'/*': {'origins': '*'}})
#app.route('/')
def index():
return 'Hello World!'
#app.route('/recData',methods=['GET','POST'])
def recData():
if request.method=='POST':
return '--- post ---'
if request.method=='GET':
return '--- get ---'
if __name__=='__main__':
app.run(port=5001, debug=True)
You can set a proxy in vue.config.js
module.exports = {
devServer: {
proxy: 'http://127.0.0.1:5001',
}
}
there is a good article about it in this link: https://medium.com/js-dojo/how-to-deal-with-cors-error-on-vue-cli-3-d78c024ce8d3
Add this to vue.config.js and restart your server after the configuration change.
devServer: {
proxy: {
"/": {
target: "http://localhost:5001",
ws: false,
changeOrigin: true,
logLevel: 'debug'
}
}
Use this in your component.
let url = "/recData";
let payload = {
firstName: "Fred",
lastName: "Flintstone"
}
axios.post(url, payload)
.then(res=>{
console.log(res);
})
.catch(err=>{
console.log(err);
});
I hope it works and I was able to help you.

Post form data from React handle submit function to python API?

I'm extremely new to React and Python and just trying to do a simple post from a react form to my Python API that will interface with a mongoDB.
I have a form in react that invokes a handleSubmit function on submit. I want the handleSubmit function to POST to my Python API running on port 5000. My react app is running on port 8080.
The handleSubmit looks like this:
handleSubmit(event) {
const axios = require('axios');
const baseUrl = 'http://localhost:5000'
axios.post('http://localhost:5000/api/create', JSON.stringify(params))
.end((error, response) => {
if (!error && response) {
console.log('got a valid response from the server')
} else {
console.log(`Error fetching data from the server: `, error)
}
});
event.preventDefault();
}
Python endpoint code:
#app.route('/api/create', methods=['POST'])
def create(self):
if request.method == 'POST':
print(request.args.get('exp_title'))
return True
return False
When I click the button, my python API endpoint isn't reached because react is trying to post to a route on port 8080. What am I missing?
I've tried using a regular ajax call and get the same result. At one point, I did something and got a CORS error in the browser, but I can't remember how I did that.
To enable cors, you need to install pip install -U flask-cors,
here is the website: https://flask-cors.readthedocs.io/en/latest/
or you can define cors in proxy in your reactjs package.json like here:
https://facebook.github.io/create-react-app/docs/proxying-api-requests-in-development
Once you install cors in your python app, try this:
Python app:
#app.route('/api/', methods=['POST', 'GET'])
def api_post():
if request.method == 'POST':
print('post app')
req = request.json
print(req)
return jsonify(name='john')
React app:
function App() {
const [todos, setTodos] = useState(null);
const [value, setValue] = useState('');
function handleSubmit(e) {
e.preventDefault();
const data = { name: value };
console.log('submit');
console.log(value);
fetch('http://127.0.0.1:5000/api/', {
method: 'POST',
headers: {
'Content-type': 'application/json',
},
body: JSON.stringify(data),
})
.then(res => res.json())
.then(res => console.log(res));
}
function handleValue(e) {
setValue(e.target.value);
}
return (
<section id="app">
<form action="" onSubmit={handleSubmit}>
<input type="text" onChange={handleValue} />
<button> submit </button>
</form>
</section>
);
}
render(<App />, document.querySelector('#root'));

Ajax: Unable to send Json object to bottle webservice

I am trying to understand how the Ajax call works.
I am sending a Json object to a bottle python webservice as an URL.
$.ajax({
type: "POST",
data: {"jstring": JSON.stringify(output)},
url: "http://localhost:8080/salesvolume" ,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data){
$('#container').highcharts(data);
},
error: function() {
alert("Something is not OK")
},
});
The above snippet is my Ajax Call. output is the Json object that I intend to send to the server.
#app.post('/salesvolume')
def salesvolume(db):
jsonstring = request.forms.get('jstring')
_jsonparams = json.loads(jsonstring)
_studios = _jsonparams.Studios
ret = `Some Json`
return json.loads(ret)
app.run(server='paste', host='localhost', port=8080, debug=True, reloader=True)
And this is my Web Service code snippet.
I get a Status Code: HTTP/1.0 500 Internal Server Error
I have been following the Bottle and Jquery documentations but Im just not able to crack this.
Any help on this will be really greatful.
Consider the following things:
1) In JS, change the url to simply: /salesvolume.
2) In Python, remove the arg - db from the salesvolume function definition. Or else you might get this err (a 500 error):
TypeError: salesvolume() takes exactly 1 argument (0 given)
<myServerIP> - - [30/Jul/2015 13:31:27] "POST /salesvolume HTTP/1.1" 500 1328
3) Check indentation. Python it is! I guess
ret = Some Json and
return json.loads(ret) needs indentation (they should be inside the salesvolume function)
I wrote this similar stuff and it seems to be working:
Python:
from bottle import *
import json, requests
#route('/')
def atHome():
return template('index')
#route('/salesvolume', method="POST")
def salesvolume():
#your processings here...
ret = '{"key":"val"}'
return json.loads(ret)
run(host='0.0.0.0', port=8093, debug=True, reloader=True)
index.tpl and JS:
<html>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<body>
<button onclick=ajaxF()>click</button>
</body>
<script>
function ajaxF(){
$.ajax({
type: "POST",
data: {"jstring": JSON.stringify("blah")},
url: "/salesvolume" ,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data){
console.log('success');
console.log(data)
},
error: function() {
console.log("Something is not OK");
},
});
}
</script>
</html>
Hope it helps!
The following code worked for me in an app using bottle (sends some data to python and dispatches some data back as JSON from python to js):
js:
$.post('/getData', {myStringInput:dataToSendtoBottle}, function(data){
var myJson = JSON.parse(data) //myOutput is dispatched back to js as JSON
});
python:
#route('/getData', method='POST')
def getData():
myDataReceivedfromJs = request.forms.get('myStringIput')
if myDataReceivedfromJs:
myStringOutput = 'OK'
myOutput = json.dumps(myStringOutput)
return myOutput

Categories

Resources