If you only want to convert to specific timezone, use localize. and forget normalize.

just use

tz2 = timezone("Asia/Seoul")
dt = datetime.datetime(year=2017, month=4, day=29, hour=8, minute=35, second=10)
dt2 = tz2.localize(dt)

utc_timestamp = dt2.timestamp()

this will calculate including DST time

but If you are going to do arithmetic operation(- or +) to your datetime object and It crosses DST start or end time,

you should use normalize(dt) to fix the utc offset.


refer to

https://github.com/newvem/pytz/blob/master/pytz/tzinfo.py

def normalize():

 '''Correct the timezone information on the given datetime

If date arithmetic crosses DST boundaries, the tzinfo

is not magically adjusted. This method normalizes the

tzinfo to the correct one.

To test, first we need to do some setup

>>> from pytz import timezone

>>> utc = timezone('UTC')

>>> eastern = timezone('US/Eastern')

>>> fmt = '%Y-%m-%d %H:%M:%S %Z (%z)'

We next create a datetime right on an end-of-DST transition point,

the instant when the wallclocks are wound back one hour.

>>> utc_dt = datetime(2002, 10, 27, 6, 0, 0, tzinfo=utc)

>>> loc_dt = utc_dt.astimezone(eastern)

>>> loc_dt.strftime(fmt)

'2002-10-27 01:00:00 EST (-0500)'

Now, if we subtract a few minutes from it, note that the timezone

information has not changed.

>>> before = loc_dt - timedelta(minutes=10)

>>> before.strftime(fmt)

'2002-10-27 00:50:00 EST (-0500)'

But we can fix that by calling the normalize method

>>> before = eastern.normalize(before)

>>> before.strftime(fmt)

'2002-10-27 01:50:00 EDT (-0400)'

'''



Error

expires = pickle.load(f)
EOFError: Ran out of input


Solution

remove flask_session folder, and restart flask


ref

https://github.com/pallets/flask/issues/2216

monkey.patch_all(thread=False)

Remove "thread=False".

This makes thread hanging.


Refer to usage of pymongo + gevent on below site

http://api.mongodb.com/python/current/examples/gevent.html

https://stackoverflow.com/questions/7166998/pymongo-gevent-throw-me-a-banana-and-just-monkey-patch

They are telling,

"By default, PyMongo uses threads to discover and monitor your servers’ topology (see Health Monitoring). If you execute monkey.patch_all() when your application first begins, PyMongo automatically uses greenlets instead of threads."


monkey patch all

1. 어느 위치에 써줘야할까?

문서에 보면 가능한 젤 위에 patch all코드를 쓰라고한다. 근데 상식적으로, import 모듈을 해놓고 패치를 해야 로드된걸 패치시키는게 아닐까? 라는 의문을 같게 된다.

대답은 맞다. 그렇지만 맨위에 쓰는게 맞다 이다.

왜냐면, monkey patch 를 지원하는 standard library들은 순서가 어찌되었건 몽키패치를 지원한다. 

from gevent.monkey import is_module_patched
from gevent import monkey;monkey.patch_all()
import socket
import threading
print(is_module_patched("socket"))
print(is_module_patched("threading"))

결과:

True
Ture

import socket
import threading
from gevent import monkey;monkey.patch_all()

print(is_module_patched("socket"))
print(is_module_patched("threading"))

결과:

True
True

그렇지만 몽키패치를 지원하지 않는 3rd library들은 위험할수도 있기 때문에 가급적 패치올을 맨위에 써서 영향이 안가도록 맨위에 쓰라는 것이다.


2. patch_all(thread=False) 

thread patch는 기본적으로 True다. thread가 몽키패치되게되면, threading을 쓰는 부분을 thread가 아니라 gevent에서 지원하는 Greenlet object로 바뀌게된다. 

일단 큰 차이는 context switching 시점이다.

thread는 내가 원하는 시점에 명시적으로 context switching을 하는게 아니라 os 스케줄에 따라서 context switching이 되어 쓸데없는 비용을 소비하게 될 확률이 높다.

그러나 greenlet object는 명시적 sleep이나 library의 io에 패치된 경우에 한해서 context switching이 된다.

참고로, windows 10에서는 maximum recursive error가 나오면서 patch_all 함수가 실패한다. 이때 thread=False 옵션을주면 잘 동작하게 된다. 아마 윈도우10에서는 thread패치를 완벽히 지원하지 않는것 같다. 


reference

1. https://stackoverflow.com/questions/39537004/gevent-monkey-patching-order

2. https://stackoverflow.com/questions/15556718/greenlet-vs-threads


'python' 카테고리의 다른 글

flask save session error  (0) 2017.12.05
python3 flask + pymongo + gevent, locust testing hangs  (0) 2017.09.26
gevent monkey patch all, code location  (0) 2017.09.14
flask with gevent monkey patch all  (0) 2017.07.26
flask gevent spawn use a lot of memory  (0) 2017.04.05
websocket with gunicorn  (0) 2017.03.03

Problem:

 - content length mismatched(ERR_CONTENT_LENGTH_MISMATCH)

 - response string truncated (cut off)


If you are using flask with gevent monkey patch all and you got such a problem above, 

than you should use gevent wsgi instead of flask app.run


For example..

from gevent import monkey

monkey.patch_all()

from flask import Flask

from gevent import wsgi


app = Flask(__name__)


@app.route('/')

def index():

  return 'Hello World'


server = wsgi.WSGIServer(('127.0.0.1', 5000), app)

server.serve_forever()

reason:

flask is not for aysnc future model, so if you want to use asynchronous for http or any socket use, than you should use gevent wsgi

'python' 카테고리의 다른 글

python3 flask + pymongo + gevent, locust testing hangs  (0) 2017.09.26
gevent monkey patch all, code location  (0) 2017.09.14
flask with gevent monkey patch all  (0) 2017.07.26
flask gevent spawn use a lot of memory  (0) 2017.04.05
websocket with gunicorn  (0) 2017.03.03
gunicorn vs uwsgi  (0) 2017.01.20

If you use http request or something using socket in gevent spawn,
you should make a limit of file open count. use python resource. like this,

import resource
resource.setrlimit(resource.RLIMIT_NOFILE, (1024, 1024))

Otherwise, It will consume all your memory as much as it can by consuming all file count that it can consume as specified on limit.conf (/etc/security/limit.conf)

But requests still consumes a lot of memory.. I just decided to use tornado instead of flask+gevent+requests

'python' 카테고리의 다른 글

gevent monkey patch all, code location  (0) 2017.09.14
flask with gevent monkey patch all  (0) 2017.07.26
flask gevent spawn use a lot of memory  (0) 2017.04.05
websocket with gunicorn  (0) 2017.03.03
gunicorn vs uwsgi  (0) 2017.01.20
flask async response  (0) 2017.01.04

reference: http://d.hatena.ne.jp/Malan/20121007

flask + gevent websocket + gunicorn

실행 방법은

gunicorn --bind 0.0.0.0:yourwebsocketport -w 2 -k "geventwebsocket.gunicorn.workers.GeventWebSocketWorker" yourappfilename:app

으로 실행하면 아주 잘 되야한다.


그러나 쟁점은 gunicorn 실행시

if __name__ == "__main__" 에 걸리지 않는다는것이다.

걸리게 하려면 yourappfilename을 __main__대신 넣어주면 된다.


if __name__ == "yourappfilename"

그리고 실행하면 Address already in use를 만날수 있다.

그렇다면 살며시 이부분을 주석처리해준다.

# server = pywsgi.WSGIServer((myIP, config.NOTI_WS_PORT), app, handler_class=WebSocketHandler)
# server.serve_forever()


'python' 카테고리의 다른 글

flask with gevent monkey patch all  (0) 2017.07.26
flask gevent spawn use a lot of memory  (0) 2017.04.05
websocket with gunicorn  (0) 2017.03.03
gunicorn vs uwsgi  (0) 2017.01.20
flask async response  (0) 2017.01.04
functools.wraps에 대해  (0) 2015.04.15

- 보통 퍼포먼스를 보면 아무래도 pure C기반의 uwsgi가 pure python인 gunicorn보다 빨라보입니다. 간혹 uwsgi가 느리다는 비교가있는데 이는 gunicorn은 워커를 gevent로 하면 몽키패치를 지가 app서버에 해버리는데 반해 uwsgi는 app서버 코드에 몽키패치를 해줘야함을 모르고 테스트할 결과로 보여지네요.

- 사용성 측면에서 uwsgi가 좀더 복잡하고 코어 갯수에 따라 configure를 잘못하면 오히려 성능저하가될 우려가 보이네요.

- 도큐먼트는 gunicorn이 훨깔끔


*참고로 gunicorn, uwsgi모두 앞단에 nginx를 쓰는케이스가 많이 있습니다. 이는
DDos 공격방지, static file전송 효율성등때문이라고 합니다. 그리고 gunicorn document에서도 말하고 있는 nginx buffering기능때문입니다. 

nginx에도 설명이 잘나와있지만 nginx buffering에 대해 좀더 설명하자면,

client - nginx - app servers

이 구조에서 client에 response를 전송하는데 nginx buffer가 없고 클라이언트가 response 패킷을 천천히 받으면 그 영향이 app server한테까지 끼쳐서 그 process는 블락이되어 다른 패킷을 처리 못하게 됩니다. 

하지만 nginx buffer가 있다면 nginx는 app server에게 response패킷을 모두 받을때까지 client에게 응답하지 않고 app server에게 다 받은후 client에게 응답을 보냅니다. 따라서 slow client를 만나더라도 app server는 블락이 되지않을 수 있는것이죠.


*추가로 볼만한것

- Backend Architechtures(https://gist.github.com/ngocphamm/5849994)

- ELB+nginx+appservers(http://amazonwebservices21.blogspot.kr/2015/07/system-architecture-to-deploy-django.html)

'python' 카테고리의 다른 글

flask gevent spawn use a lot of memory  (0) 2017.04.05
websocket with gunicorn  (0) 2017.03.03
gunicorn vs uwsgi  (0) 2017.01.20
flask async response  (0) 2017.01.04
functools.wraps에 대해  (0) 2015.04.15
Apple Push Notification Service(APNs) python modules  (0) 2015.04.07

Gevent monkey patch makes requests to react asynchronous.

Environment: mac OS 10.11.5, python 3.5.2, gevent==1.1.2, requests==2.12.4

Example:

from flask import Flask

from gevent.pywsgi import WSGIServer
from gevent import monkey

import requests
# need to patch sockets to make requests async
monkey.patch_all()

app = Flask(__name__) # pylint: disable=invalid-name
app.debug = True


@app.route('/test')
def test(requests_counter=[0]): # pylint: disable=dangerous-default-value
"""Asynchronous non-blocking streaming of relatively large (14.5MB) JPG
of Seattle from wikimedia commons.
"""
requests_counter[0] += 1
request_num = requests_counter[0]
url = 'http://www.google.com'
app.logger.debug('started %d', request_num)
rsp = requests.get(url)
app.logger.debug('finish %d', request_num)

return rsp.text


def main():
http = WSGIServer(('', 5000), app.wsgi_app)
http.serve_forever()


if __name__ == '__main__':
main()

Result:

started 1

started 2

started 3

started 4

started 5

started 6

finish 4

finish 5

finish 3

finish 6

finish 1

finish 2

'python' 카테고리의 다른 글

websocket with gunicorn  (0) 2017.03.03
gunicorn vs uwsgi  (0) 2017.01.20
flask async response  (0) 2017.01.04
functools.wraps에 대해  (0) 2015.04.15
Apple Push Notification Service(APNs) python modules  (0) 2015.04.07
Getting specific timezone timestamp from time string  (0) 2015.01.20

functools.wraps는 보통 python fucntion을 wrapping할 때 원래 function의 정보들을 유지 시키기 위해서 사용된다.

간단한 wrapper 코드를 보자.


import functools


def print_iam_wrapper(method):

    @functools.wraps(method)        ----- 1

    def wrapper(*args, **kwargs):    ----- 2

        print "I'm wrapper"

        return method(*args, **kwargs)


    return wrapper


@print_iam_wrapper

def iam_func():

    print 'iam_func'


print iam_func.__name__                  ----- 3 

iam_func()                                       ----- 4


여기서 1번을 제거해도 4번의 결과는 같다. 하지만 3번의 결과는 다르다.

wraps가 하는 일은 wraps, update_wrapper, partial 코드를 살펴보면 이해가 간다.

(3개의 function에 대한 코드는 아래에 두겠다.)

1번 decorator가 실행될때 method가 넘어가서 넘어오는 것은 결국 wraps의 결과인 partial() 리턴값인데 이것은 newfunc 이다. 그렇다면 1번은 @newfunc가 되었다고 볼 수 있다.


그리고 @newfunc에 파라미터로 넘어가는 것은 아래있는 wrapper function이 된다. 이때 newfunc은 update_wrapper를 실행하고 있으므로 이는 또한 @update_wrapper와 같다. 다만 이때 wrapped로 처음에 전달된 method 즉 iam_func이 넘어가 있을 것이다. 결국 의미는 wrapped에 설정되어있는 '__module__', '__name__', '__doc__', '__dict__' attritbute를 wrapper에 셋팅하여 던져주는 것이다.



* 참고) update_wrapper, wraps, partial

WRAPPER_ASSIGNMENTS = ('__module__', '__name__', '__doc__')

WRAPPER_UPDATES = ('__dict__',)

def update_wrapper(wrapper,

                   wrapped,

                   assigned = WRAPPER_ASSIGNMENTS,

                   updated = WRAPPER_UPDATES):

    for attr in assigned:

        setattr(wrapper, attr, getattr(wrapped, attr))

    for attr in updated:

        getattr(wrapper, attr).update(getattr(wrapped, attr, {}))

    # Return the wrapper so this can be used as a decorator via partial()

    return wrapper


def wraps(wrapped,

          assigned = WRAPPER_ASSIGNMENTS,

          updated = WRAPPER_UPDATES):


    return partial(update_wrapper, wrapped=wrapped,

                   assigned=assigned, updated=updated) 


def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfunc























'python' 카테고리의 다른 글

gunicorn vs uwsgi  (0) 2017.01.20
flask async response  (0) 2017.01.04
functools.wraps에 대해  (0) 2015.04.15
Apple Push Notification Service(APNs) python modules  (0) 2015.04.07
Getting specific timezone timestamp from time string  (0) 2015.01.20
Shallow copy VS Deep copy  (0) 2014.08.27

+ Recent posts