Re: [sqlalchemy] do_connect listener called couple of times

2022-03-22 Thread Srinu Chp
Hello Simon,

I tried your suggestion as POC:

def setup_event_handlers(engine):
@event.listens_for(engine, 'do_connect')
def receive_do_connect(dialect, conn_rec, cargs, cparams):
print("inside do_connect")
print('password %s' % cparams['password'])
try:
print("inside try")
return cx_Oracle.connect(*cargs, **cparams)
except Exception as e:
print("inside catch")
cparams['password'] = "NewPassword"
return cx_Oracle.connect(*cargs, **cparams)

Every time except block is triggered even I set correct password in Except 
block. As per document once cparams password set it should pass new 
password for new request. Can you please suggest if I miss anything here?

Regards,
Pydi

On Tuesday, March 22, 2022 at 9:33:57 AM UTC-7 Srinu Chp wrote:

> Hello Simon,
>
> Thank you very much for detail information.
>
> Regards,
> Pydi
>
> On Tuesday, March 22, 2022 at 3:11:34 AM UTC-7 Simon King wrote:
>
>> I don't know anything about Airflow. Are you sure that each of these
>> tasks is running inside the same Python interpreter/process? I see
>> Airflow can distribute tasks among workers:
>>
>> https://airflow.apache.org/docs/apache-airflow/stable/executor/index.html
>>
>> This sounds like a problem that is going to be very specific to your
>> deployment environment. If you have multiple worker processes, you're
>> going to need some way to distribute the new password to each of the
>> workers (eg. a shared cache)
>>
>> But regardless of that, you're still not following the pattern from
>> the documentation. I don't understand why you are creating a new
>> engine inside your do_connect handler. You should be creating a
>> cx-Oracle connection and returning it. The parameters passed to the
>> do_connect handler have already been parsed out of the connection
>> string. So for example, if your connection string includes a
>> "password=some_password" parameter, then cparams will have a
>> "password" key with the value "some_password". The same cparams
>> dictionary will be passed to the do_connect handler each time, so if
>> you mutate the dictionary (eg. by updating the "password" key), the
>> next call to the handler will contain the new value.
>>
>> If each task invocation is creating a new engine using a connection
>> string that is out of date, then none of that will help you, but that
>> would be an Airflow problem, not an SQLAlchemy problem.
>>
>> Simon
>>
>> On Mon, Mar 21, 2022 at 8:27 PM Srinu Chp  wrote:
>> >
>> > Hello Simon,
>> >
>> > I tried POC approach in my project where we are using Airflow using 
>> sqlalchemy to connect to db. Here is the event code:
>> >
>> > @event.listens_for(engine, "do_connect")
>> > def receive_do_connect(dialect, conn_rec, cargs, cparams):
>> > global SQL_ALCHEMY_CONN
>> > log.info("receive_do_connect called for user AIRFLOW.")
>> > log.info("user details DB: {}".format(SQL_ALCHEMY_CONN))
>> > # creating new engine to valide using cx_oracle driver
>> > engine_new = 
>> create_engine(f'{SQL_ALCHEMY_CONN}/?encoding=UTF-8=UTF-8', 
>> max_identifier_length=128)
>> > try:
>> > with engine_new.connect() as conn:
>> > log.info(conn.scalar("select sysdate from dual"))
>> > SQL_ALCHEMY_CONN = "testNew_try"
>> > except Exception as e:
>> > # check for invalid user/pwd error
>> > if search('ORA-01017', str(e)):
>> > log.info("receive_do_connect exception occurred during engine 
>> connection e: {}".format(e))
>> > ...
>> > //update with new password
>> > SQL_ALCHEMY_CONN = "testNew_except"
>> > # this log print new value with updated password
>> > log.info("user details DB after update in except block: 
>> {}".format(SQL_ALCHEMY_CONN))
>> > cparams['New password']
>> >
>> > global SQL_ALCHEMY_CONN value is set during initialization. Once 
>> password is rotated I am trying to update the SQL_ALCHEMY_CONN so that next 
>> request will not go in except block. Every time logs print old 
>> SQL_ALCHEMY_CONN value even value is update in except block.
>> >
>> > second approach:
>> > I tried to set env variable in except block:
>> > os.environ['AIRFLOW__CORE__SQL_ALCHEMY_CONN']
>> > env variable also refer to old value even after updating in except 
>> block.
>> >
>> > Can you please suggestion?
>> > Regards,
>> > Pydi
>> > On Monday, March

Re: [sqlalchemy] do_connect listener called couple of times

2022-03-21 Thread Srinu Chp
Hello Simon,

Thank you for prompt response. I really appreciate your help. I am trying 
to achieve password rotation and we are using secret client to fetch new 
password. I tried do_connect event and fetch new password from secret 
client, working as expected but we are facing performance issue as we are 
every time connecting to secret client(3~5sec for each request). Instead I 
am trying to achieve if connect fails then fetch from secret client. 

I tried with handle_error event, when i get error check for invalid 
user/pwd and update session with latest engine. This approach also did not 
help

Any insights are highly appreciated. Please suggest best approach.

Regards,
Pydi
On Monday, March 21, 2022 at 2:22:04 AM UTC-7 Simon King wrote:

> I don't really understand what's going on in your code, but you seem
> to be calling engine.connect() inside your "do_connect" event handler.
> I would expect that to trigger another "do_connect" event, which in
> turn will call engine.connect() again, which will trigger another
> "do_connect" event, and so on. I'm surprised the application gets as
> far as it does. Maybe the exception handler inside receive_do_connect
> is allowing it to stumble on.
>
> Simon
>
> On Mon, Mar 21, 2022 at 4:51 AM Srinu Chp  wrote:
> >
> > Hello Team,
> >
> > I tried to create a standalone application POC for sqlalchemy to db 
> connection. When I registered do_connect event, I see event is triggered 
> couple of times for one call:
> > sqlalchemy_connection.py
> >
> > import os
> > import cx_Oracle
> > from sqlalchemy import create_engine
> > from sqlalchemy import event
> >
> > cx_Oracle.init_oracle_client(lib_dir=os.environ.get("HOME") + 
> "/Downloads/instantclient_19_8")
> > SQLALCHEMY_CONN = "test"
> > count = 0
> > engine = None
> > def connect_db(pwd):
> > global count
> > global engine
> > print(SQLALCHEMY_CONN)
> > username = "ADMIN"
> > password = pwd
> > dsn = "pydidb_high"
> > engine = create_engine(
> > f'oracle://{username}:{password}@{dsn}/?encoding=UTF-8=UTF-8', 
> max_identifier_length=128)
> > setup_event_handlers(engine)
> >
> > def setup_event_handlers(engine):
> > @event.listens_for(engine, 'do_connect')
> > def receive_do_connect(dialect, conn_rec, cargs, cparams):
> > print("inside do_connect")
> > global count
> > try:
> > with engine.connect() as conn:
> > print("inside do_connect try block")
> > print(conn.scalar("select sysdate from dual"))
> > count += 2
> > except Exception as e:
> > print("inside do_connect except block")
> > count += 1
> >
> > def db_connect_test():
> > print(engine)
> > with engine.connect() as conn:
> > print(conn.scalar("select sysdate from dual"))
> >
> > gevent_sync.py
> >
> > import gevent
> > import random
> > import sqlalchemy_connection
> >
> > def task(pid):
> > gevent.sleep(random.randint(0,2)*0.001)
> > print('Task %s done' % pid)
> > sqlalchemy_connection.connect_db(**)
> > sqlalchemy_connection.db_connect_test()
> >
> > def synchronous():
> > for i in range(1,2):
> > task(i)
> > # sqlalchemy_connection.connect_db(**)
> >
> > def asynchronous():
> > threads = [gevent.spawn(task, i) for i in range(2)]
> > gevent.joinall(threads)
> >
> > print('Synchronous:')
> > synchronous()
> > print('count %s ' % sqlalchemy_connection.count)
> >
> > # print('Asynchronous:')
> > # asynchronous()
> > # print('count %s' % sqlalchemy_connection.count)
> >
> > Output:
> >
> > Synchronous:
> > Task 1 done
> > test
> > Engine(oracle://ADMIN:***@pydidb_high/?encoding=UTF-8=UTF-8)
> > inside do_connect
> > inside do_connect
> > inside do_connect
> > inside do_connect
> > inside do_connect
> > inside do_connect
> > inside do_connect
> > inside do_connect
> > inside do_connect
> > inside do_connect
> > inside do_connect
> > inside do_connect
> > inside do_connect
> > inside do_connect
> > inside do_connect
> > inside do_connect except block
> > inside do_connect try block
> > 2022-03-21 04:39:47
> > inside do_connect try block
> > 2022-03-21 04:39:49
> > inside do_connect try block
> > 2022-03-21 04:39:51
> > inside do_connect try block
> > 2022-03-21 04:39:54
> > inside do_connect try block
> > 2022-03-21 04:39:56
> > inside 

[sqlalchemy] do_connect listener called couple of times

2022-03-20 Thread Srinu Chp
Hello Team,

I tried to create a standalone application POC for sqlalchemy to db 
connection. When I registered do_connect event, I see event is triggered 
couple of times for one call:
*sqlalchemy_connection.py*

import os
import cx_Oracle
from sqlalchemy import create_engine
from sqlalchemy import event

cx_Oracle.init_oracle_client(lib_dir=os.environ.get("HOME") + 
"/Downloads/instantclient_19_8")
SQLALCHEMY_CONN = "test"
count = 0
engine = None
def connect_db(pwd):
global count
global engine
print(SQLALCHEMY_CONN)
username = "ADMIN"
password = pwd
dsn = "pydidb_high"
engine = create_engine(
f'oracle://{username}:{password}@{dsn}/?encoding=UTF-8=UTF-8', 
max_identifier_length=128)
setup_event_handlers(engine)

def setup_event_handlers(engine):
@event.listens_for(engine, 'do_connect')
def receive_do_connect(dialect, conn_rec, cargs, cparams):
print("inside do_connect")
global count
try:
with engine.connect() as conn:
print("inside do_connect try block")
print(conn.scalar("select sysdate from dual"))
count += 2
except Exception as e:
print("inside do_connect except block")
count += 1

def db_connect_test():
print(engine)
with engine.connect() as conn:
print(conn.scalar("select sysdate from dual"))

*gevent_sync.py*

import gevent
import random
import sqlalchemy_connection

def task(pid):
gevent.sleep(random.randint(0,2)*0.001)
print('Task %s done' % pid)
sqlalchemy_connection.connect_db(**)
sqlalchemy_connection.db_connect_test()

def synchronous():
for i in range(1,2):
task(i)
# sqlalchemy_connection.connect_db(**)

def asynchronous():
threads = [gevent.spawn(task, i) for i in range(2)]
gevent.joinall(threads)

print('Synchronous:')
synchronous()
print('count %s ' % sqlalchemy_connection.count)

# print('Asynchronous:')
# asynchronous()
# print('count %s' % sqlalchemy_connection.count)

*Output:*

Synchronous:
Task 1 done
test
Engine(oracle://ADMIN:***@pydidb_high/?encoding=UTF-8=UTF-8)
inside do_connect
inside do_connect
inside do_connect
inside do_connect
inside do_connect
inside do_connect
inside do_connect
inside do_connect
inside do_connect
inside do_connect
inside do_connect
inside do_connect
inside do_connect
inside do_connect
inside do_connect
inside do_connect except block
inside do_connect try block
2022-03-21 04:39:47
inside do_connect try block
2022-03-21 04:39:49
inside do_connect try block
2022-03-21 04:39:51
inside do_connect try block
2022-03-21 04:39:54
inside do_connect try block
2022-03-21 04:39:56
inside do_connect try block
2022-03-21 04:39:59
inside do_connect try block
2022-03-21 04:40:01
inside do_connect try block
2022-03-21 04:40:04
inside do_connect try block
2022-03-21 04:40:09
inside do_connect try block
2022-03-21 04:40:15
inside do_connect try block
2022-03-21 04:40:17
inside do_connect try block
2022-03-21 04:40:19
inside do_connect try block
2022-03-21 04:40:21
inside do_connect try block
2022-03-21 04:40:24
2022-03-21 04:40:26
count 29

highly appreciate any inputs.
Regards,
Pydi

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sqlalchemy/08096636-06c4-478f-a54d-0bc8f71db414n%40googlegroups.com.


Re: [sqlalchemy] password rotation after engine created

2022-02-04 Thread Srinu Chp
Thank you Mike for the help.

On Friday, February 4, 2022 at 1:49:45 PM UTC-8 Mike Bayer wrote:

> you would most easily amend the "costly operation" part of it to cache the 
> result for a given period of time, so that you can get this password when 
> you need it from local memory.   the generated password should be delivered 
> with an approximate expiration time so that you can store it locally within 
> the scope of that timeframe.
>
> otherwise, opt to fully replace the connect function, use oracle connect 
> with try/except, then connect again with the new password, use the hook 
> example at 
> https://docs.sqlalchemy.org/en/14/core/engines.html#fully-replacing-the-dbapi-connect-function
>   
>
>
>
>
> On Fri, Feb 4, 2022, at 12:03 PM, Srinu Chp wrote:
>
> Hello Mike,
>
> Thank you very much for prompt response. yes, I tried to update password 
> and every thing works fine but every time I need to fetch new password from 
> secret client is costly operation. So, is there any way I can catch  
> "ORA-01017: invalid username/password; logon denied" and try password 
> update instead of every time calling secret client to fetch same password.
>
> Regards,
> Srinu
>
> On Friday, February 4, 2022 at 8:56:49 AM UTC-8 Mike Bayer wrote:
>
>
> we have a recipe for this scheme here:
>
>
> https://docs.sqlalchemy.org/en/14/core/engines.html#generating-dynamic-authentication-tokens
>
> no need to connect() inside the event handler, just update the parameters 
> with the new password.
>
> On Fri, Feb 4, 2022, at 11:14 AM, Srinu Chp wrote:
>
> Hello Everyone,
>
> We have application, while start up we initialize prepare engine args, 
> configure orm. Once engine created we keep in session. Recently peer team 
> introduced password rotation and for now as work around we are manually 
> restarting the docker container to fetch latest password from secret 
> client. I am trying to automate the process and implemented  
> @event.listens_for(engine, "do_connect"). I have impression that every db 
> connection will be fetched from pool and if pool exhausted or expired then 
> we fetch new connection. But every time do_connect listener is called and 
> it is taking 3-5 secs. For complex tasks it is taking long time. Can you 
> please suggest best approach for password rotation? I tried below code, 
> before password change I get this error "RecursionError: maximum recursion 
> depth exceeded while calling a Python object"
>
> @event.listens_for(engine, "do_connect")
> try:
> log.info("receive_do_connect success")
> return engine.connect()
> except SQLAlchemyError as err:
> log.info("error receive_do_connect ")
> 
>
> Regards,
> Srinu
>
>
> -- 
> SQLAlchemy - 
> The Python SQL Toolkit and Object Relational Mapper
>  
> http://www.sqlalchemy.org/
>  
> To post example code, please provide an MCVE: Minimal, Complete, and 
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
> description.
> --- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to sqlalchemy+...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/sqlalchemy/3884b3c2-8814-494b-9d47-bc1304ab748cn%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/sqlalchemy/3884b3c2-8814-494b-9d47-bc1304ab748cn%40googlegroups.com?utm_medium=email_source=footer>
> .
>
>
>
> -- 
> SQLAlchemy - 
> The Python SQL Toolkit and Object Relational Mapper
>  
> http://www.sqlalchemy.org/
>  
> To post example code, please provide an MCVE: Minimal, Complete, and 
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
> description.
> --- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to sqlalchemy+...@googlegroups.com.
>
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/sqlalchemy/d0ce3a81-c53f-4884-9258-c4a2d742e39cn%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/sqlalchemy/d0ce3a81-c53f-4884-9258-c4a2d742e39cn%40googlegroups.com?utm_medium=email_source=footer>
> .
>
>
>

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sqlalchemy/a97fc121-ace6-4511-82f2-cce99e059585n%40googlegroups.com.


Re: [sqlalchemy] password rotation after engine created

2022-02-04 Thread Srinu Chp
Hello Mike,

Thank you very much for prompt response. yes, I tried to update password 
and every thing works fine but every time I need to fetch new password from 
secret client is costly operation. So, is there any way I can catch  
"ORA-01017: invalid username/password; logon denied" and try password 
update instead of every time calling secret client to fetch same password.

Regards,
Srinu

On Friday, February 4, 2022 at 8:56:49 AM UTC-8 Mike Bayer wrote:

> we have a recipe for this scheme here:
>
>
> https://docs.sqlalchemy.org/en/14/core/engines.html#generating-dynamic-authentication-tokens
>
> no need to connect() inside the event handler, just update the parameters 
> with the new password.
>
> On Fri, Feb 4, 2022, at 11:14 AM, Srinu Chp wrote:
>
> Hello Everyone,
>
> We have application, while start up we initialize prepare engine args, 
> configure orm. Once engine created we keep in session. Recently peer team 
> introduced password rotation and for now as work around we are manually 
> restarting the docker container to fetch latest password from secret 
> client. I am trying to automate the process and implemented  
> @event.listens_for(engine, "do_connect"). I have impression that every db 
> connection will be fetched from pool and if pool exhausted or expired then 
> we fetch new connection. But every time do_connect listener is called and 
> it is taking 3-5 secs. For complex tasks it is taking long time. Can you 
> please suggest best approach for password rotation? I tried below code, 
> before password change I get this error "RecursionError: maximum recursion 
> depth exceeded while calling a Python object"
>
> @event.listens_for(engine, "do_connect")
> try:
> log.info("receive_do_connect success")
> return engine.connect()
> except SQLAlchemyError as err:
> log.info("error receive_do_connect ")
> 
>
> Regards,
> Srinu
>
>
> -- 
> SQLAlchemy - 
> The Python SQL Toolkit and Object Relational Mapper
>  
> http://www.sqlalchemy.org/
>  
> To post example code, please provide an MCVE: Minimal, Complete, and 
> Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
> description.
> --- 
> You received this message because you are subscribed to the Google Groups 
> "sqlalchemy" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to sqlalchemy+...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/sqlalchemy/3884b3c2-8814-494b-9d47-bc1304ab748cn%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/sqlalchemy/3884b3c2-8814-494b-9d47-bc1304ab748cn%40googlegroups.com?utm_medium=email_source=footer>
> .
>
>
>

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sqlalchemy/d0ce3a81-c53f-4884-9258-c4a2d742e39cn%40googlegroups.com.


[sqlalchemy] password rotation after engine created

2022-02-04 Thread Srinu Chp
Hello Everyone,

We have application, while start up we initialize prepare engine args, 
configure orm. Once engine created we keep in session. Recently peer team 
introduced password rotation and for now as work around we are manually 
restarting the docker container to fetch latest password from secret 
client. I am trying to automate the process and implemented  
@event.listens_for(engine, "do_connect"). I have impression that every db 
connection will be fetched from pool and if pool exhausted or expired then 
we fetch new connection. But every time do_connect listener is called and 
it is taking 3-5 secs. For complex tasks it is taking long time. Can you 
please suggest best approach for password rotation? I tried below code, 
before password change I get this error "RecursionError: maximum recursion 
depth exceeded while calling a Python object"

@event.listens_for(engine, "do_connect")
try:
log.info("receive_do_connect success")
return engine.connect()
except SQLAlchemyError as err:
log.info("error receive_do_connect ")


Regards,
Srinu

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sqlalchemy/3884b3c2-8814-494b-9d47-bc1304ab748cn%40googlegroups.com.