Cancel current/active query in Ruby on Rails

百般思念 提交于 2019-12-11 03:32:40

问题


In my project I am running a massive query returning lots of data. Due to the size of this query, the runtime sometimes exceeds 1 minute. Ignoring other issues this may create, is there any way to cancel a currently running query?

For example, the user starts the query and is redirected to a standard 'Loading Results...' page. If they then decide that they no longer want the results, they can click a 'Cancel' button which will somehow terminate the running query.

Is this possible and how can it be done?

Thanks!


回答1:


Try using pg_cancel_backend.

From the docs:

Cancel a backend's current query. You can execute this against another backend that has exactly the same role as the user calling the function. In all other cases, you must be a superuser.




回答2:


The only way I know of is to restart the database, although sometimes you can send a cancel signal, depending on the DB setup. You could look at the rack-timeout gem perhaps?

The real issue is that your query should not take that long, and I would strongly advise not approaching the problem this way. A far better way would be to examine the query and attempt to optimise it. There are few, if any queries that should legitimately be taking >1 minute to complete. Get a dump of the data onto your local machine and run EXPLAIN on the query to find the bottlenecks. I have gotten large 142s queries down to <3s by adding the right indexes, so I would be amazed if you cannot get the same effect.




回答3:


I did something like this recently (adding a "cancel" button to our application). The plpgsql function I hacked together is below, which is basically a wrapper around the pg_cancel_backend() function.

Caveats:

1). Your application must create an unique id (or UUID) and pass that in to the function as the "p_uid" parameter.

2). I hardcoded the application user (that doesn't change).

3). Postgresql 9.0+ (this was created for 9.2, untested in any earlier versions)

4). Security could be tightened up a bit in the function.

CREATE OR REPLACE FUNCTION public.cancel_user_query(p_uid TEXT, OUT retval BOOLEAN) RETURNS boolean
AS $function$
DECLARE
BEGIN
    /*  The pg_sleep() call at the start is because if a user issues a query
        then promptly tries to kill it, it will likely not have shown up in the
        pg_stat_activity view yet (there is a delay before it appears).
        XXX: The GUC setting "track_activities" *MUST* be enabled for this to work.
    */

    retval := FALSE;
    IF ( current_setting('track_activities')::BOOLEAN IS NOT TRUE ) THEN
        RAISE WARNING '[PUBLIC.CANCEL_USER_QUERY] - "track_activities" *MUST* be enabled for this to work';
        RETURN;
    END IF;

    /* In a system under regular high load, this might need to be bumped higher than 2 seconds */
    PERFORM pg_sleep(2); 

    WITH q AS ( SELECT pid FROM pg_stat_activity WHERE LOWER(usename) = 'YOUR_APP_USER' AND application_name = p_uid AND state <> 'idle' )
    SELECT pg_cancel_backend(pid) AS retval
    INTO retval
    FROM q;

    if ( retval IS NOT TRUE ) then
        retval := FALSE;
    end if;

    RETURN;

EXCEPTION
    WHEN others THEN
        RAISE WARNING '[PUBLIC.CANCEL_USER_QUERY] - ERROR: %',sqlerrm;
        retval := FALSE;
        RETURN;
END;
$function$ LANGUAGE plpgsql SECURITY DEFINER;

On click of the "Cancel query" button, the application executes the function and checks the returned status. Eg. SELECT retval FROM public.cancel_user_query('asifdaqiwaviafasdf') retval



来源:https://stackoverflow.com/questions/18067095/cancel-current-active-query-in-ruby-on-rails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!