Taming outbound call rate

Door Rob van den Berg In Oracle

Suppose you are the developer of a database service which can be called any number of times. This database service itself just registers the call, and is allowed to immediately make an outbound call to another service, for example to enhance information presented by the initial inbound call.

No suppose the interactions with this service are restricted by a limited outbound call rate, which means you should take care it doesn’t exceed a certain maximum per second. You’d then want to optimize the number of times the API for this service is called to exactly match this allowed maximum.

For simplicity, let’s assume the service API should not be called more often than 25 times per second.

Requirements

  • There’s a stored procedure which represents the referenced outbound API, we will call it my_api_request();
  • There’s a table registering each successfull call to the API by the timestamp of it’s call;
  • Querying the table should reveal how many calls per second were made, which should ideally be optimized to 25 times per second.

Solution setup

The solution I present heavily relies on the ordered non-cached sequence feature. The idea is to construct an expression consisting of both a time representation including date, hour, minute and seconds complemented with a value which cycles through 25 different values using the modulo function. Of course, the value of 25 corresponds to the required maximum of 25 calls per second.

Hence, first we create an ordered sequence

create sequence my_ordered_seq order nocache
/

And then we create the API-calls logging table

create table my_api_requests
( time_of_request    timestamp    default systimestamp not null 
, seq_id             number(15)   default my_ordered_seq.nextval
, req_id             varchar2(21) generated always as 
                                  ( substr
                                    ( to_char(time_of_request,'YYYYMMDD-HH24MISS')
                                      ||'.'
                                      ||lpad(mod(seq_id,25),3,'0')
                                    , 1
                                    ,21
                                    )
                                  )
, constraint my_api_requests_limit unique (req_id)
)

As you will see, each time a value is inserted to the table, a subsequent number is derived from the ordered sequence.
If there a more than 25 inserts within the same second, the module function will result in a previously used expression. This will cause a unique key constraint violation, effectively prohibiting the outbound call rate to exceed the required maximum.

Solution test

Contents of timertest.sql, which is parameterized script to allow us to test for the specified N number of seconds:

define p_nrof_sec = &1.
declare
  c_nrof_seconds constant pls_integer := &p_nrof_sec.;
  l_time_ends constant date := sysdate + c_nrof_seconds/(24*3600);

  l_succeeded_count pls_integer := 0;
  l_skipped_count pls_integer := 0;
 
  procedure do_api_request
  is
  pragma autonomous_transaction;
  begin
    insert into my_api_requests (time_of_request) values (default);
    l_succeeded_count:=l_succeeded_count+1;
    -- call my_api_request() here ;
    commit;
  exception
    when others
    then -- too many inserts per unit of time
    l_skipped_count:=l_skipped_count+1;
  end do_api_request;

begin
  while sysdate < l_time_ends
  loop
    do_api_request;
  end loop;
  dbms_output.put_line ( 'succeeded api requests: '||l_succeeded_count);
  dbms_output.put_line ( 'skipped api requests: '||l_skipped_count);
end;
/

select   to_char(time_of_request,'YYYYMMDD-HH24MISS')
,        count(*)
from     my_api_requests
group by to_char(time_of_request,'YYYYMMDD-HH24MISS')
/

Output

SQL> @timertest 10
succeeded api requests: 250
skipped api requests: 11679

PL/SQL procedure successfully completed.

TO_CHAR(TIME_OF_REQUEST,'YYYYMMDD-HH24MISS')  COUNT(*)
--------------------------------------------- --------
20160530-154401                                     25
20160530-154402                                     25
20160530-154403                                     25
20160530-154404                                     25
20160530-154405                                     25
20160530-154406                                     25
20160530-154407                                     25
20160530-154408                                     25
20160530-154409                                     25
20160530-154410                                     25
10 rows selected.

SQL>

Conclusion

We succesfully created a mechanism to both restrict and optimize the number of times the outbound service has been called!

Meer informatie

rob-van-den-berg1

Rob van den Berg

Oracle Database Consultant

+31 6 22 98 69 27 Stuur Rob een e-mail

Reacties

Er zijn nog geen reacties op dit bericht.

Plaats een reactie

Dit veld is verplicht.

Vul een geldig e-mailadres in.

Dit veld is verplicht.