Giter VIP home page Giter VIP logo

fast_bitrix24's Issues

slow() не работает

Текущий алгоритм при поступлении нескольких одновременных запросов ждем по всем по ним параллельно, а должен ждать последовательно. Нужно использовать asyncio.lock().

  • Написать тесты на slow()

Перейти на dict в результатах get_by_ID()

Сейчас get_by_ID возвращает list of tuples вида

[
    (ID_1, result_1),
    (ID_2, result_2),
    (ID_3, result_3),
    ...
]

Кажется, было бы гораздо проще, если бы он возвращал dict вида

{
    ID_1: result_1,
    ID_2: result_2,
    ID_3: result_3,
    ...
}

Это бы упростило некоторые операции с результатами вызова этого метода:

  1. Когда нужно отбросить айдишники и оставить только массив результатов:
  • сейчас:
[single_result for ID, single_result in get_by_ID_results]
  • после перехода на dict:
get_by_ID_results.values()
  1. Когда в результатах нужно найти конкретный ID:
  • сейчас:
[single_result for ID, single_result in get_by_ID_results 
 if ID == ID_to_look_for][0]
  • после перехода на dict:
get_by_ID_results[ID_to_look_for]

Ошибка в примерах

В примере https://github.com/leshchenko1979/fast_bitrix24#%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5
deals = b.get_all('crm.deal.get', params={
'select': ['', 'UF_'],
'filter': {'CLOSED': 'N'}
})
Выдает ошибку, т.к. метод crm.deal.get ожидает id в параметрах.
Если заменить метод crm.deal.get на crm.deal.list, то пример отрабатывает, как и ожидается.

Может, сделать один мегаметод для регулировки pool_size, requests_per_second и cautious_mode?

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

  • Что если сделать context wrapper Bitrix.slow(), внутри которого можно задать свой pool_size и requests_per_second?
  • Убрать кастомные параметры из __init__?
  • Убрать настройку autobatch и везде соответственно подчистить код, убрав if self._autobatch:

Рефакторинг

https://app.genmymodel.com/api/repository/leshchenko/fast-bitrix24

  • UserRequest и производные
  • SingleServerRequest
  • MultipleServerRequest и проивзодные
  • Весь метод _request_list перенести в абстрактный класс, который будет содержать шаблонный метод, который будет обращаться к методам, переопределяемым в конкретных классах

Что, если в call() был передан batch, и запустился autobatch?

  • Очевидно, что в таких случаях нужно отключать автобатчевание. Также, если было передано несколько батчей списком, нужно отключать упаковку в батчи, но список выполнять параллельно.
  • Описать в доке, что при подаче списка батчей порядок выполнения не гарантирован

ServerRequestHandler.run()

Метод берет на вход корутину, которую оборачивает в код, который оборачивает вызов этой корутины в:

  • asyncio.run()
  • async with self:

Будет вызываться из реаизацийUserRequestAbsract.run().

call() vs get_all()

Почему нельзя везде использовать call()? Чем get_all() лучше?

Стратегия выборки в get_all()

Текущая стратегия выборки в get_all() с использованием параметра start, хотя и позволяет использовать параллелизм, но замедляет работу сервера. Ее применение может быть неоптимальным при условиях:

  1. требуется сложная фильтрация с выгрузкой небольшого количества записей
  2. полный список сущностей (без фильтров) содержит большое количество записей

Для таких случаев более оптимальной может быть стратегия, описанная тут:
https://dev.1c-bitrix.ru/rest_help/rest_sum/start.php

Можно дать пользователю в get_all() параметр strategy, который он будет использовать, чтобы выбрать стратегию. Либо можно после первого вызова в зависимости от размера параметра filter в params и от total, возвращаемого в первом ответе, выбирать стратегию автоматически. Алгоритм выбора стратегии можно подобрать опытным путем.

get_all() не работает с параметром limit()

Выдаёт больше лимита, что вполне объяснимо, так как алгоритм get_all() не анализирует наличие лимита в params, а только ориентируется на total в ответах сервера.

  • Можно сделать параметр отдельный параметр limit, который можно будет вызывать как при обращении к get_all(), так и в 'params'.
  • Метод должен конструировать запросы к серверу таким образом, чтобы вовремя остановиться.
  • Опасность представляет возможный возврат дублей сервером при отсутствии сортировки. в параметрах запроса

details -> params

В доке Битрикса используется термин "параметры".

Рефакторинг slow()

slow перенести в класс Bitrix / ServerResponseHandler - это даст возможность запускать одновременно несколько экземпляров класса Bitrix, решить проблему несовместимости с асинхронными вызовами и правильно наладит инкапсуляцию.

Задержка между батчами - "горшочек, не вари"

Попытка создать более 2500 лидов за один вызов call() вызывает 500 Internal server error. Задержка в 5 сек. между такими вызовами позволяет обходить эту проблему.

  • Сделать в Bitrix.__init__ параметр requests_per_second, который будет оверрайдить умолчание в 2 сек. и будет публичным (то есть, пользователь сможет его менять между вызовами, если ему предстоят тяжелые вызовы на создание объектов).

Сортировка результатов

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

Например, по get_all() предполагается, что элементы отсортированы по ID, а по get_by_ID и call, что порядок элементов в результатах вызова такой же, как и во входных массивах.

Однако есть развилки:

get_all()

  • А мы уверены, что в каждом списке будет ID? Или, более общо, элемент, по которому будет сортировка? Как нам понять, есть он или нет?

Решение:

- [ ] Если есть ID, то сортировать по нему. Если его нет, то не сортировать. - решил, что в этом нет потребности. Сортировка потребует конверсии ID в int, а это может быть неожиданным для пользователя.

get_by_ID()

  • Что возвращать?
    • dict вида ID: results?
      • сломается имеющийся код
      • но поиск в результатах вызова будет очень прост
    • tuple вида (ID, results), где tuple отсортирован по ID?
      • код не сломается
    • просто список списков результатов, отсортированный также, как и входящий список
      • код сломается
      • поиск в результатах вызова также будет прост
      • кажется, что список списков - это менее понятно, чем dict
      • будет хорошая аналогия со структурой результатов, возвращаемых методом call()

Решение:

  • Пока что сортировать текущий list of tuples
    • Оказалось, что в этом нет смысла, пока в _get_by_ID на входе происходит дедупликация списка ID через преобразование его в set.
      • [х] Нужно выбрать один из вариантов:
        • при получении дублей на вход поднимать исключение,
        • не обращать внимание на дубли и делать запросы столько раз, сколько запросил пользователь - отличная идея для начала, так как она убирает неожиданное для пользователя поведение
          • Убрать дедупликацию ID_list на входе
          • Сортировать результаты согласно порядок элементов в ID_list
        • отказаться от идеи сортировки списка результатов
          • в том числе, путем #45

call()

  • Если сортировать результаты так же, как и запросы, то как это сделать через код?

  • Надо сделать preserve_IDs, на место IDs подавать номер элемента item_list. Потом по этому номеру делать сопоставление результатов в выходном массиве.

  • Поправить всю доку касательно сортировки

Ожидаем, что сервер Битрикса будет возвращать dict после выполнения батча, а он возвращает list

Что вызывает исключения в текущем коде.

В частности, list возвращается вместо dict при попытке вызвать crm.deal.get со списком ID.

  • Построить больше тестов, проверяющих формат возвращаемых сервером данных в results
  • Соответствующим образом адаптировать _request_list

в get_by_ID() добавить параметр "ID_field_name"

Тогда внутри метода при формировании запросов будет использоваться не метка "ID", а метка ID_field_name.

Пример - когда нужно выгрузить дела по сделке (метод crm.activity.get), то отборочным признаком является не ID, а OWNER_ID.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.