Проблема с кэшем и двойным вызовом апишки

Главные вкладки

Аватар пользователя towi towi 10 апреля 2022 в 10:05

Сделал модуль который отображает погоду в конкретном городе.

Но получил такие замечения по коду:
1. Интересный вопрос, а что происходит с данными вашего кеша, если на сайт сначала заходит человек из города Madrid, а потом Dublin?

Я так понимаю имеется в виду что человек из Дублина когда зайдет на сайт будет видеть погоду Мадрида, потому что она возьмется из кэша. Но я ведь кладу данные в кэш чтобы не было слишком много запросов, сделал один раз запрос, положил данные в кэш и следующие разы уже брал данные из кэша.

2. В небольшой функции вы дважды вызываете конечную точку http://ip-api.com/json/. Что происходит, когда сайт посещает тысяча человек в минуту?

Тут, я вообще не понимаю в чем проблема. Если имелось ввиду что будет исчерпан лимит подключения к ресурсу, то как решить эту проблему? В функции getCity() данные класть в кэш также как я делаю в функции build()? Но тогда вылезает та же проблема, что и в первом замечании, если на сайт зайдет человек из другого города, то возьмутся данные из кэша (название города Мадрид) а не название его настоящего города. Как тогда быть?
_________________________________________________________________________________
Подскажите пожалуйста что нужно исправить в моем коде?
Ниже напишу немного сокращенный код моего рhp файла. Полный вариант здесь: https://phpsandbox.io/n/sweet-forest-1lew-1wmof

<?php
// ....
use Drupal\Core\Cache\CacheBackendInterface;
use 
GuzzleHttp\Client;

//....

  

public function getCity() {

    

$ip '193.62.157.66';  // статический чисто для теста

    

try {
      
$response_ip $this->httpClient->get('http://ip-api.com/json/' $ip);
      
$response_data_ip $response_ip->getBody();
      
$data_ip json_decode($response_data_ip);

      if (

$data_ip->status == 'success') {
        return 
$data_ip->city;
      }
      else {
        return 
$this->configFactory->get('sydneypro_weather.settings')->get('weather_city');
      }

    }
    catch (

RequestException $e) {
      return 
FALSE;
    }

  }

  public function 

build() {
    
$client $this->httpClient;
    
$api_key $this->configFactory->get('sydneypro_weather.settings')->get('weather_api_key');
    
$cid 'sydneypro_weather';
    
$weather_config $this->configFactory->get('sydneypro_weather.settings');

    if (!

$weather_config) {
      
$this->logger->get('sydneypro_weather')->error('Config "sydneypro_weather.settings" is missing4');
      return [];
    }

    if (empty(

$api_key) || empty($this->getCity())) {
      return [
        
'#type' => 'markup',
        
'#markup' => $this->t('Please enter your API key and City in the Admin panel to see the weather'),
      ];
    }

    try {
      if (

$cache $this->cacheBackend->get($cid)) {
        
$data $cache->data;
      }
      else {
        
$response $client->get('http://api.openweathermap.org/data/2.5/weather?q=' $this->getCity() . ',&appid=' $api_key '&units=metric');
        
$response_data $response->getBody();
        
$data json_decode($response_data);
        
$this->cacheBackend->set($cid$data$this->time->getRequestTime() + 21600);
      }

      

$build = [
        
'#theme' => 'weather_block',
        
'#data' => $data,
        
'#attached' => [
          
'library' => [
            
'sydneypro_weather/sydneypro_weather',
          ],
        ],
      ];

      return 

$build;

    }
  

// ....

?>

Лучший ответ

Аватар пользователя OldWarrior OldWarrior 10 апреля 2022 в 21:56
1

Навскидку. Как минимум нужен уникальный $cid для кеширования каждого результата запроса getCity() по отдельному городу. Иначе "не взлетит". У вас общий $cid для всех запросов, что сводит кеширование результатов только к последнему полученному.

Комментарии

Аватар пользователя ivnish ivnish 10 апреля 2022 в 10:28
1

towi wrote: Я так понимаю имеется в виду что человек из Дублина когда зайдет на сайт будет видеть погоду Мадрида

Да

towi wrote: Что происходит, когда сайт посещает тысяча человек в минуту?

Проблем с эти может быть несколько. Во-первых вы можете исчерпать лимит подключений к ресурсу (если лимиты есть). Во-вторых при обращении к этому ресурсу, если соединение подвиснет, то и загрузка вашего сайта подвиснет.

Аватар пользователя towi towi 10 апреля 2022 в 11:19

Да

Но я ведь кладу данные в кэш чтобы не было слишком много запросов, сделал один раз запрос, положил данные в кэш и следующие разы уже брал данные из кэша.

Проблем с эти может быть несколько. Во-первых вы можете исчерпать лимит подключений к ресурсу (если лимиты есть). Во-вторых при обращении к этому ресурсу, если соединение подвиснет, то и загрузка вашего сайта подвиснет.

Если имелось ввиду что будет исчерпан лимит подключения к ресурсу, то как решить эту проблему? В функции getCity() данные класть в кэш также как я делаю в функции build()? Но тогда вылезает та же проблема, что и в первом замечании, если на сайт зайдет человек из другого города, то возьмутся данные из кэша (название города Мадрид) а не название его настоящего города. Как тогда быть?

Аватар пользователя OldWarrior OldWarrior 10 апреля 2022 в 21:56
1

Навскидку. Как минимум нужен уникальный $cid для кеширования каждого результата запроса getCity() по отдельному городу. Иначе "не взлетит". У вас общий $cid для всех запросов, что сводит кеширование результатов только к последнему полученному.