В этом году мы уже писали на Хабре про наш проект SmartCalls.io – визуальный конструктор звонков, созданный для бизнес-пользователей. Проект решает задачу бизнеса по массовым обзвонам клиентов: создается визуальный сценарий звонка, загружается Excel-файл с номерами телефонов и далее создается кампания по обзвону. Запускается кампания – начинается обзвон клиентов; в любой момент можно смотреть статистику, приостанавливать кампанию, подкручивать настройки. Клиенты были довольны, пока не выяснилось, что иногда надо обзванивать не просто много людей, а ОЧЕНЬ, ОЧЕНЬ много. Под катом – суть проблемы и как мы ее победили с помощью хайпового (не безосновательно) языка программирования.


Проблема


Изначально обработка файлов была реализована на PHP 7.1 – это был очевидный выбор, так как весь API SmartCalls был написан именно на нем. Работа с колл-листами имела одно ограничение – файл должен содержать не более 10 тысяч заполненных строк. Это ограничение было с самого начала в SmartCalls и, впрочем, не было критичным. До определенного момента.

У одного крупного банка появилась потребность в очень больших кампаниях по обзвону: требовалось обзванивать гораздо больше 10 тысяч пользователей. Конечно, ничто не мешало разбивать большие файлы на несколько маленьких и загружать их поочередно, но заставлять клиентов вот так страдать – не наш метод. К слову о поочередной загрузке – если наш клиент уже запустил кампанию по обзвону и вдруг захотел добавить в нее пользователей, то он может легко это сделать. Это весьма удобно, потому что не надо останавливать обзвон или запускать отдельную кампанию по новым пользователям. Но стоит понимать, что возможность дозагрузки не задумывалась как способ грузить большие файлы вручную, по кускам.

Итак, у команды появилась задача – реализовать загрузку больших файлов в кампании по обзвону.

Решение


Мы очень компетентны в разработке на Java – например, частично API Voximplant реализован на этом языке; также мы хорошо умеем в PHP (см. пример выше – подсказывает Капитан Очевидность). То есть мы могли быстро закрыть эту задачу, используя один из этих языков, однако мы давно думали расширить наш стек технологий, и тут как нельзя кстати мы вспомнили про Go: он достаточно быстрый (хорошо работает с памятью), многопоточный и ему не нужен рантайм, т.к. Go компилируется в исполняемый бинарник. Вдобавок можно сказать про размер контейнеров, но об этом чуть позже…

В итоге мы написали микросервис на языке Go, который принимает листы большого размера (тестировали до 300 тысяч строк) и формата (xls, xlsx и все их разновидности). Настало время для подробностей.

Реализация


Когда клиент загружает в кампанию SmartCalls файл >10 тысяч строк, за него берется микросервис. Он принимает на вход указатели:

  • на файл, загруженный в S3-хранилище;
  • на кампанию, в которую этот файл нужно загрузить.

Затем микросервис пробегает по файлу, бьет его на чанки по 10 тысяч строк (максимум для платформы) и каждый чанк в виде csv-файла загружает в S3-хранилище, делая о каждом чанке заметки в БД (путь до файла, количество строк). Каждый чанк обрабатывается и загружается в отдельном потоке, что дает дополнительный прирост в скорости выполнения.

Для чтения Excel-файлов использовали опенсорсные библиотеки от tealeg и extrame. Хорошо, что у них не только много звезд, но еще и свежие коммиты :)

import (
  "github.com/tealeg/xlsx"
  "github.com/extrame/xls"
  // прочие импорты
)

И все бы хорошо, но не обошлось без нюансов. В ходе разработки выяснилось, что xlsx и xls, созданные в разных редакторах, сильно отличаются по форматам и правилам работы с ними. Пришлось делать много тестов – OpenOffice, Excel разных версий, LibreOffice, Google Sheets, чтобы научить микросервис приводить файлы к единому виду – CSV. После того, как микросервис «прожевывает» большой файл и превращает в CSV, в работу включается API SmartCalls и уже работает с этим csv-файлом. Для микросервиса мы оставили лимит в 300 тысяч строк, так как он сильно покрывает нужды клиентов, а с бОльшими потребностями мы и вовсе не сталкивались.

В итоге реализация отлично показала себя на тестах и препроде, после чего мы выкатили это в прод.

Вывод


Наша команда всегда старается быстро выкатывать новые фичи/доработки, потому что мы хотим, чтобы довольные клиенты таковыми и оставались. Задача с большими файлами была не просто очередным челленджем для нас, но еще и хорошим поводом внедрить в проект Go, к которому мы давно присматривались. Помимо быстрой разработки и скорости работы, Go дает нам задел на будущее, когда мы начнем внедрять контейнеры (чтобы делать бесшовные апдейты и вот это всё), которые у этого языка весьма легковесные. Про контейнеры мы обязательно напишем отдельно, stay tuned :)

Комментарии (21)


  1. xmdy
    28.09.2018 11:58

    Вот у вас на картинке красивая схема, а про нее ни слова. Как реализовывали, сколько данных хранит?


    1. aylarov
      28.09.2018 12:05
      +1

      1. xmdy
        28.09.2018 12:41
        +1

        Это фронт, бэк более интересен. Как обрабатывается, хранится, что будет, если сделать цепочку из 150 шагов, и тд.


        1. aylarov
          28.09.2018 13:44

          Да в виде JSON, а потом JSON преобразуется в JavaScript-сценарии Voximplant


  1. VIkrom
    28.09.2018 12:31
    +5

    У нас есть большая экспертиза в разработке на JAVA

    Эксперти?за (от лат. expertus — опытный, сведущий) — исследование, проводимое лицом, сведущим в науке, технике, искусстве или ремесле, привлечённым по поручению заинтересованных лиц, в целях получения ответа на вопросы, требующие специальных познаний.

    Одолели «экспертизы». Извините.


    1. nvpushkarskiy2 Автор
      28.09.2018 12:35
      +3

      Вы правы, слово «экспертиза» нельзя использовать в значении «опыт».
      Однако так стали часто делать и я было принял это за устоявшийся отраслевой сленг, поэтому и применил в статье. Но все же это не сленг, а просто… неправильно.

      Спасибо, поправил этот фрагмент.


      1. acmnu
        01.10.2018 13:19
        +1

        В языке нет понятия правильно и неправильно. Есть только используется и не используется. И экспертиза в этом "неправильном" смысле используется давольно давно, поэтому все вы нормально написали изначачально. Даже тот, кто не любит это слово, вас сразу понял.


    1. WinPooh73
      28.09.2018 17:15
      +2

      Хуже «экспертизы» в значении «опыт» только «функционал» в значении «функциональность».


  1. Alert123
    28.09.2018 12:40
    +2

    Не знаю чем ваши клиенты довольны, может просто количеству звонков клиентам. Но отношение к себе они такими звонками только портят.
    Банки уже достали подобной рекламой. Раньше дослушивал чтобы узнать по какому поводу, все таки человек звонит. А сейчас на первых словах сразу ясно что робот, сбрасываю. Так они снова и снова звонят, и с разных номеров.


    1. irbisadm
      28.09.2018 12:58

      Кроме тупых роботизированых дозвонов клиентам с желанием что-то впарить, есть еще и автоматизация. Например, доставки или уведомлений о записи к врачу или парикмахеру. Ну и про робота: пару лет еще и не будет ясно.


    1. hMartin
      28.09.2018 12:58

      Кстати, круто выручает антиспам штука на андроиде. У меня почти все спам-звонки отсекаются, ну т.е они помечаются спамными и я их просто не беру, кому надо — смску напишут :)


    1. Perlovich
      28.09.2018 13:13
      +1

      А сейчас на первых словах сразу ясно что робот, сбрасываю.


      Когда звонит даже не оператор, а робот, и просит оставаться на линии и подождать живого оператора — это вообще за гранью добра и зла. Альфа-банк таким злоупотребляет.


      1. aylarov
        28.09.2018 13:44

        Это криво настроенный предиктивный обзвон


    1. wlr398
      28.09.2018 14:36

      А как становится ясно, что робот?
      Тоже звонят постоянно из банков, из опсосов и т.п., с разных номеров.
      Здороваются, по имени-отчеству отбращаются, спрашивают удобно или нет.
      На роботов вроде не похоже. Но тоже сразу понятно, что спамеры, ничего не отвечаю, даю отбой и в чёрный список, часто и номер по маске, если бомбят с диапазона колцентра.
      Надоели ужасно.


  1. Perlovich
    28.09.2018 13:12

    del


  1. Moxa
    28.09.2018 13:23

    сколько времени ушло на разработку микросервиса? как быстро обрабатываются xlsx тысяч на сто строк? я как-то пару лет назад столкнулся с такой задачей, жавовский apache poi вообще не справлялся, жрал гигабайты памяти и думал несколько минут


    1. nvpushkarskiy2 Автор
      29.09.2018 12:45

      По времени разработки – примерно 4 рабочих дня, включая тесты/обкатку.
      Про тайминг смогу ответить попозже, если вы не против :) В понедельник вас устроит?


      1. Moxa
        29.09.2018 12:59

        Да, конечно =)


  1. Neuyazvimy1
    28.09.2018 13:35

    Название статьи не подтвердили. Нужен бенчмарк go и excel.


  1. alexhott
    28.09.2018 15:04

    у меня стояла задача обзванивать должников, списки по 3- 5 тысяч позиций, тоже сначала было на php
    Но почему то от екселя сразу отказались.
    Было сделано два варианта:
    1 PHP скрипт вызывает процедуру на биллиноговом MSSQL, получает список и звонит.
    2 ПОльзователь в интерфейсе задает параметры — по параметрам обращение к базе и вывод списка, пользователь удаляет лишние строки и запускает обзвон.


  1. prospero78su
    01.10.2018 09:04

    … и ему не нужен рантайм, т.к. Go компилируется в исполняемый бинарник.

    Ну нельзя же так. Такая успешная компания, делает такие замечательные ляпы.
    Но Go одобряю. Лучше, чем C, C++, python.