0

I have an app built with Flask & Plotly Dash - a bit of a mashup to enable subscriptions for a dashboard via PayPal.

I can't replicate the error in development, but I am sometimes getting an error in the Heroku logs when someone signs up, but can't get through the paypal subscription process. One person mentioned the paypal loading is in an endless loop, but otherwise not clear on the issue.

The error from the logs is this, but the link isn't helpful to me:

output_value = func(*args, **kwargs)  # %% callback invoked %%
File "/app/index.py", line 347, in successful
conn.execute(upd)
File "/app/.heroku/python/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1263, in execute
return meth(self, multiparams, params, _EMPTY_EXECUTION_OPTS)
File "/app/.heroku/python/lib/python3.9/site-packages/sqlalchemy/sql/elements.py", line 323, in _execute_on_connection
return connection._execute_clauseelement(
File "/app/.heroku/python/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1452, in _execute_clauseelement
ret = self._execute_context(
File "/app/.heroku/python/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1814, in _execute_context
self._handle_dbapi_exception(
File "/app/.heroku/python/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1995, in _handle_dbapi_exception
util.raise_(
File "/app/.heroku/python/lib/python3.9/site-packages/sqlalchemy/util/compat.py", line 207, in raise_
raise exception
File "/app/.heroku/python/lib/python3.9/site-packages/sqlalchemy/engine/base.py", line 1771, in _execute_context
self.dialect.do_execute(
File "/app/.heroku/python/lib/python3.9/site-packages/sqlalchemy/engine/default.py", line 717, in do_execute
cursor.execute(statement, parameters)
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) SSL SYSCALL error: EOF detected

[SQL: UPDATE users SET subscribed=%(subscribed)s WHERE users.id = %(id_1)s]
[parameters: {'subscribed': 0, 'id_1': '11'}]
(Background on this error at: https://sqlalche.me/e/14/e3q8)

line 347 in successful from index.py refers to the following code. Line 347 is the conn.execute in the 3rd last else statement in the code.

@app.callback(
    Output('url_login', 'pathname')
    , [Input('login-button', 'n_clicks')]
    , [State('uname-box', 'value')
    , State('pwd-box', 'value')])
def successful(n_clicks, username, password):
    conn = psycopg2.connect(
        dbname=dbname,
        user=dbuser,
        password=dbpassword,
        host=dbhost,
        port=dbport,
        sslmode=os.environ['sslmode']
    )
    c = conn.cursor()
    if paypalenv == "Live":
        environment = LiveEnvironment(client_id=client_id, client_secret=client_secret)
    else:
        environment = SandboxEnvironment(client_id=client_id, client_secret=client_secret)
    client = PayPalHttpClient(environment)   
    user = Users.query.filter_by(username=username).first()
    
    if user:
        if check_password_hash(user.password, password):
            login_user(user)
            cuid = current_user.get_id()
            c.execute(f"select orderid from users where id = {cuid}")
            oid = c.fetchone()
            c.execute(f"select status from users where id = {cuid}")
            status = c.fetchone()
            if oid[0] is not None:
                act = SubscriptionActivate(oid[0])
                try:
                    response = client.execute(act)
                except:
                    response = None
                if response is not None:
                    if response.result.status == 'ACTIVE':
                        upd = update(Users).where(Users.id == cuid).values(subscribed=1, status= 'ACTIVE')
                        conn = engine.connect()
                        conn.execute(upd)
                        conn.close()
                    else:
                        upd = update(Users).where(Users.id == cuid).values(subscribed=0)
                        conn = engine.connect()
                        conn.execute(upd)
                        conn.close()
                return '/subscribe'
            else:
                upd = update(Users).where(Users.id == cuid).values(subscribed=0)
                conn = engine.connect()
                conn.execute(upd)
                conn.close()
            return '/subscribe'
        else:
            pass
    else:
        pass

Appreciate any help, can't find any answers on this and not sure how to test / replicate the issue!

davidism
  • 121,510
  • 29
  • 395
  • 339
Pete Drennan
  • 522
  • 1
  • 6
  • 15
  • It's a socket error. Is the query taking too long? It might be timing out. – Selcuk Nov 30 '21 at 01:36
  • Pretty sure you want a `conn.commit()` after each DDL statement and before `conn.close()`, but I'm not saying that's the cause of the error. – mechanical_meat Nov 30 '21 at 01:42
  • @Selcuk I'll admit I don't know. Perhaps it is timing out if the person / paypal is taking too long? Any ideas how to fix that? – Pete Drennan Nov 30 '21 at 02:13
  • @mechanical_meat i'll give it a go, but similarly not sure if it'll help! after the `conn.execute(upd)` line? – Pete Drennan Nov 30 '21 at 02:18
  • Yes, exactly right after that line. The idea is that you're committing that change to the database. I'm not sure if there's an autocommit setting anywhere in SQLAlchemy connecting code, so this may or may not do anything. – mechanical_meat Nov 30 '21 at 02:20
  • There is not much you can do if the operation takes too long. Maybe try increasing the default timeout using the `connect_timeout` argument in your `psycopg2.connect` call: https://stackoverflow.com/a/27641996/2011147 – Selcuk Nov 30 '21 at 02:26
  • @mechanical_meat getting "AttributeError: 'Connection' object has no attribute 'commit'" – Pete Drennan Nov 30 '21 at 09:12
  • It's not an attribute, it's a function/method. Try instead: `conn.commit()` – mechanical_meat Nov 30 '21 at 11:38
  • @mechanical_meat yep that's why i tried! – Pete Drennan Dec 01 '21 at 02:44

0 Answers0