`` тут нічого немає.
@drawoharaя ❤️ це! << натисніть мене 🐛 🫖 🧚
/defeating-the-sticky-wicket-of-api-limits-with-a-javascript-worker-army
опубліковано: 2013-11-12

TL;DR

коли у вас дуже багато роботи на сервері через обмеження API

передайте частину роботи клієнтам для виконання - відправте результати назад до вашої бази даних

проблема

минулого тижня я мав справу з (g-provider) обмеженнями API та надто великою кількістю запитів на геолокацію, що надходили з сервера(ів). Я трохи попрацював над цим, виконуючи речі на задньому плані з періодичними повторними спробами - ви знаєте: стандартні речі…

API, про яке йдеться, обмежується за IP, і документація рекомендує скористатися цим, виконуючи більшість викликів API на стороні клієнта - у js.

Тепер, у цьому конкретному випадку мені абсолютно потрібно було, щоб результати викликів API знаходилися на стороні сервера, тому я зупинився на цьому компромісному (у кількох сенсах) рішенні

рішення

припустімо, що деякі клієнти готові витрачати свій процесорний час на заповнення даних, які їх цікавлять. Простими словами, змусіть деяких своїх клієнтів виконувати завдання з черги JavaScript, щоб підготувати насос, з якого вони хочуть пити.

у моєму випадку певні вибрані інтерфейси (цікаві результатами цих робіт) виконують маленький iframe

<!-- вставте виконавця черги завдань на певні сторінки/перегляди/макети -->
<iframe height="0" width="0" style="display:none;" src="/javascript_jobs/runner"></iframe>
<!-- виконавець завдань -->
<%= javascript_include_tag :jquery %>
<%= javascript_include_tag :jobs %>
<script>
  jQuery(function(){
    jobs.complete = function(job){
      document.write('завершено ' + job.id);
      document.write('<br>');
    };
    setTimeout(function(){ jobs.start(); }, 1000);
  });
</script>

JS, необхідний для взаємодії з чергою завдань, короткий і простий

все, що він робить - це отримує завдання, виконує його та відправляє назад на сервер - дотримуючись як пропускної здатності, так і максимальної кількості завдань для виконання.

if(!window.jobs){
//
  window.jobs = {};
  window.jobs.count = 0;
  window.jobs.max = 256;
  window.jobs.throttle = 1000;
  window.jobs.complete = function(){};
//
  jobs.get_next_job = function(){
    var success = function(response){
      job = response['data']['job'];
      if(job){
        jobs.count++;
        jobs.run(job, function(job){
          if(jobs.count < jobs.max){
            setTimeout(jobs.get_next_job, jobs.throttle);
          }
        });
      }
    };
    jQuery.ajax({
      'url'     : '/api/jobs/next',
      'type'    : 'GET',
      'cache'   : false,
      'success' : success
    });
  };
//
  jobs.run = function(job, callback){
    var code = job['code'];
    var result = undefined;
    callback = callback || function(){};
    if(code){
      try{
        (function(){
          job['result'] = eval(code);
        })()
      } catch(e) {};
    }
    var url = '/api/jobs/:id'.replace(/:id/, job['id']);
    var data = {'job' : job};
    var success = function(response){
      job = response['data']['job'];
      try{
        jobs.complete(job);
      } catch(e){};
      try{
        callback(job);
      } catch(e){};
    };
    jQuery.ajax({
      'url'      : url,
      'type'     : 'PUT',
      'cache'    : false,
      'data'     : {'job'  : job},
      'dataType' : 'json',
      'success'  : success
    });
  };
//
  jobs.start = jobs.get_next_job;
}

Ця модель дозволяє нам передати завдання клієнту, і якщо він не відповість протягом певного часу, ми припускаємо, що інший клієнт може виконати це завдання.

також відомо як. завдання вважаються і ідемпотентними, і безстановими.

ось приклад завдання, що виконує геолокаційний пошук у браузері клієнта та відправляє його назад на сервер

// виконує геолокаційний пошук на google maps api та відправляє його назад на сервер
//
  <%
    address = location.raw_address
    url     = GGeocode.geocode_url_for(:address => address).to_s
  %>
  var address = <%= raw address.to_json %>;
  var url     = <%= raw url.to_json %>;
  var result;
  jQuery.ajax({
    'type'  : 'GET',
    'url'   : url,
    'cache' : false,
    'async' : false,
    'success' : function(data){
      result = data;
      jQuery.ajax({
        'type'  : 'POST',
        'url'   : '/api/geo_locations',
        'cache' : false,
        'async' : false,
        'data'  : {'address' : address, 'data' : data}
      })
    }
  });
  result;

генерування цих завдань з сервера просте

  # використовуючи чудовий gem rails_view
  code = View.render('javascript_jobs/job/geo_location.js.erb', :locals => {:location => location})
  JavascriptJob.create :code => code

тепер завдання знаходиться в черзі, і якийсь клієнт врешті-решт виконає роботу
на нашу користь.

результат

мені вдалося уникнути ліцензійного збору в розмірі 10 000 доларів і виконати багато запитів до API для насичення моїх даних за невелику ціну в складності та сплачуючи ціну евентуальної консистенції заздалегідь.

оновлення

на боксі, обмеженому 2500 запитами/день, ось що відбувається за 1 день