LINUX.ORG.RU

CLI/API к сервисам на python

 , ,


1

2

Есть несколько простых самописных сервисов на python.

Хочется иметь к ним какое-то CLI или API чтобы дёргать внутренние функции.

Но всё, на что я натыкаюсь это flask или подобное ему.

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

Посоветуйте как правильно это делается или где про это почитать?

★★

REST API - это внешний API для клиентов. В этом смысле не понятно, что означает слово «внутренние» в отношение функций.

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

Все зависит от конкретного сервиса и технических требований.

seiken ★★★★★
()
Ответ на: комментарий от seiken

Ок, на конкретном примере:

Самописный сервис, который слушает события asterisk ami, фильтрует их и складывает в SQL.

Хочется к этому сервису прикрутить возможности:

  • Складывать события не в SQL, а в файл(т.е. поменять внутреннюю переменную use_sql)
  • Спросить ami часть живо ли соединение и как давно(пнуть внутреннюю функцию и получить её выхлоп)

Понимаю, что это API, вижу, что наиболее просто будет использовать flask.

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

Скорее всего я не знаю какой-то простой истины и неправильно спрашиваю запрос у google, что мне только на rest api и выдаёт.

Flotsky ★★
() автор топика
Ответ на: комментарий от izzholtik

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

Или я слишком бегло прочитал тему по ссылке.

Flotsky ★★
() автор топика
Ответ на: комментарий от Flotsky

планирую обращаться к этому API только локально

Можно заюзать USER-сигналы: https://docs.python.org/3/library/signal.html

Если надо через HTTP, то для обработки запросов, вместо громоздких фреймворков, легко можно обойтись http.server: https://docs.python.org/3/library/http.server.html

anonymous
()
Ответ на: комментарий от Flotsky

события asterisk ami, фильтрует их

Я не знаю, что такое астериск ами, но если речь про события, значит возможны два принципиальных варианта:

  1. Есть некий явный цикл обработки событий (подождал новое событие -> прочитал -> обработал событие) Решение: после (или перед) обработкой очередного события пробовать читать (без блокировки) новую текстовую команду CLI из заранее открытого файла FIFO. По прочтении команды изменять некую структуру с рантайм настройками сервиса;

  2. Есть какая-то сторонняя либа или фреймворк, который уже используется, и явного цикла нет, а есть только коллбеки, которые реализуют обработку события. Решение: просто добавить в конец/начало коллбеков чтение и обработку команды от CLI. Получится костыльно и по-говнокодерски, но зато просто наколбасить. Надо только в коллбеки пропихивать глобальный контекст.

seiken ★★★★★
()

использовать брокер сообщений. Асинхронно, глобально, надежно.

anonymous
()
Ответ на: комментарий от Flotsky

ни знаю, мне такое решение по итогу показалось сомнительным, плюс оно гвоздями к *nix прибито, я через SOAP по локалхосту команды гоняю..

izzholtik ★★★
()
Ответ на: комментарий от seiken

после (или перед) обработкой очередного события пробовать читать (без блокировки) новую текстовую команду

Хотел бы я на этот вариант твоего авторства взглянуть.

anonymous
()
Ответ на: комментарий от izzholtik

через SOAP по локалхосту

Тут соглашусь. Готовая api библиотека явно стабильнее будет чем мои попытки с файлом общаться.

Но будет ли использование API библиотеки слишком громоздко я пока не понял.

Попробую оба варианта.

PS. ‘слишком громоздко’ может тут я сам себя путаю и нет смысла думать об этом если я пишу на python

Flotsky ★★
() автор топика
Ответ на: комментарий от izzholtik

плюс оно гвоздями к *nix прибито

а кто сказал, что любые системы должно непременно, кровь из носу делать портабельными? И потом, если речь о оффтопике, то там именованные дудки таки есть.

seiken ★★★★★
()
Ответ на: комментарий от seiken

Я джавист, что от меня останется, если убрать переносимость? (:
Ясен пень, что в современных ОС всё более-менее схоже, но разные сборки для разных ОС - это дополнительный геморрой во всех аспектах, и ещё надо для тестов виндовую машину держать..

izzholtik ★★★
()

jupyter

упс сервисов прочитал как скриптов

vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 1)

Хочется иметь к ним какое-то CLI или API чтобы дёргать внутренние функции.

Есть celery. Если кажется, что это из области пушки и воробьев, то asyncio, aiohttp, flask etc не самый плохой вариант, потому что это как раз для «API чтобы дёргать внутренние функции».

Как и связь через брокера (redis, amqp etc), тем более, что сейчас это всё поднимается в докере в «два клика».

Из совсем «нативного» чтобы не «добавлять кучу кода в небольшой скрипт», есть Pyro4

vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 6)

А вообще, конечно, сокеты для этого и придумали.

anonymous
()
Ответ на: комментарий от izzholtik

Я джавист, что от меня останется, если убрать переносимость? (:

Не расстаешь - не снеговик же ;)

Ясен пень […]

ну мы не знаем, какой сценарий у автора, и на сколько вся эта «промышленность» релевантна в его случае. Может быть он тестирует дома на коленках какую-то либу или продукт. Или в его компании он ответственнен за все, и как хочет, так и … За недостатком всей этой информации о обстоятельствах дела, я обычно рекомендую идти по пути наименьшего сопротивления (ну, типа оффтопик вместо онтопика и проч.)

seiken ★★★★★
()

Спасибо, остановился пока на flask(rest api) т.к. мне наиболее просто сейчас его будет реализовать.

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

Flotsky ★★
() автор топика
Ответ на: комментарий от Flotsky

bottle ещё посмотри — весь фреймворк в одном файле.

anonymous
()

С умеренно старыми торнадо и ptpython делал примерно так как показано ниже.
На выходе: возможность подцепившись телнетом получить ptpython-овский REPL с доступом к globals и locals основного приложения.
Где-то рядом там ещё asyncSSH валялся, но мне было не надо – доступ к порту только локальный, доступ к системе только для своих.
Аналогично с сокетом: telnet 0 <port> может любой, а как цепляться к сокету придётся объяснять.

От фласка отказался из-за его игрушечности.
У торнадо несколько специфическая документация и не поддерживается работа в качестве WSGI «клиента» (мне пофиг, но вдруг у кого фантазии на тему ХайЛоада).
Сейчас, наверное, писал бы поверх aiohttp: меньше культурных слоёв и при беглом осмотре всё нужное нашлось.

... skip ...

from ptpython.repl import embed
from prompt_toolkit.contrib.telnet.server import TelnetServer

async def interact(connection=None):
    await embed(return_asyncio_coroutine=True, globals=globals())

def interactive_shell(app, local, port):
    telnet_server = TelnetServer(interact=interact, port=port)
    telnet_server.loc = local
    asyncio.set_event_loop(asyncio.new_event_loop())
    tornado.ioloop.IOLoop.instance().start()
    telnet_server.start()
    debug("REPL started on port %s" % port)

... skip ...

# somewhere in the app init
        io = tornado.ioloop.IOLoop()
        io.add_callback(interactive_shell, app, locals(), port)
        io.start()
frob ★★★★★
()
Ответ на: комментарий от izzholtik

Предполагаю, что Вы не про API.
Если я не понял вопрос, уточните, пожалуйста.

Поскольку телнет-клиент есть в любой приличной ОС, то вопрос видимо сводится к «зачем (на стороне приложения) телнет-сервер, если достаточно голого TCP-сокета».

Телнет предлагает сравнительно простой протокол использующий передачу управляющих сигналов внутри соединения.
По умолчанию телнет-клиент работает в строчном режиме с локальным эхо:

  • на экран печатается всё, что пользователь вводит,
  • ввод отправляется на сервер одной строкой по нажатию Enter.

Так и будет работать «простейший TCP-сервер» – никакого редактирования строки, истории команд и прочих удобств.

Запустите tcpdump и подцепитесь телнетом к какой-нибудь железке.
В первом же пакете от сервера прилетит набор сигналов отключающий эхо и переключающий режим со строчного на символьный.
Телнет-клиент ответит подтверждением. В строчном режиме без эха телнет-клиент сразу отправляет ввод на сервер и не печатает его на экран.
На экране появляется то, что в ответ присылает сервер. БОльшую часть символов (буквы-цифры-итп) сервер будет тупо отправлять обратно.
Зато на некоторые будет реагировать как требуется: дополнять по табу, выдавать подсказку, поддерживать историю команд и т.д. и т.п.
Лишь бы терминал, из которого запущен телнет-клиент умел то, что надо.

Аналог телнета («и даже лучше») можно самостоятельно реализовать ручками. Но зачем?

frob ★★★★★
()
Ответ на: комментарий от frob

Наглядное объяснение:

$ telnet telehack.com
...
.basic
Dartmouth DTSS TeleBASIC (c) 1964,1966,1969,1970,1971,1979
>10 for i=0 to 3
>20 print i
>30 next i
>run
 0 
 1 
 2 
 3 
>quit

.?
...
.2048
<игра 2048>
...
^C
.zrun
...
.zrun <название игры>
...

и т.д.

http://mewbies.com/acute_terminal_fun_telnet_public_servers_watch_star_wars_play_games_etc.htm#telnet_muds

anonymous
()
Ответ на: комментарий от frob

Возможностей telnet-интерфейсов. И лучше даже не «наглядное», а «интерактивное».

Ты описал словами, а я дополнил примером.

anonymous
()
Ответ на: комментарий от Flotsky

Складывать события не в SQL, а в файл(т.е. поменять внутреннюю переменную use_sql)

Выглядит немного странным желание делать возможность переконфигурации этого на лету. Обычно это задаётся при старте приложения, тут миллион возможностей:

  1. Читать из конфигурационного файла
  2. Читать из переменной окружения
  3. Парсить аргументы командой строки при запуске сервиса

Можно комбинировать 1+2+3, есть даже вроде бы готовые комбайны для такого комбинирования.

Спросить ami часть живо ли соединение и как давно(пнуть внутреннюю функцию и получить её выхлоп)

Если надо спрашивать по http, то можно использовать flask или fastapi.

Кажется, что это будет проще любого другого варианта.

Но вообще, тут бы ещё помогло описание того, как сейчас устроен сервис.

emorozov
()

gRPC же, нет?

anonymous
()
Ответ на: комментарий от emorozov

Складывать события не в SQL, а в файл(т.е. поменять внутреннюю переменную use_sql) Выглядит немного странным желание делать возможность переконфигурации этого на лету.

Не вижу тут переконфигурации на лету.

У меня явно задано 2 способа сохранения обработанных событий

  • SQL
  • Путь в ФС для файлов

Если в конф. файле стоит флаг используй SQL, то он и будет использоваться.

До тех пор, пока не отвалится или я не попрошу(api запросом) перестать его использовать.

Т.к. события от asterisk терять не хочется, а SQL поломать в ближайшее время может потребоваться.

Flotsky ★★
() автор топика

Посоны, а вы знали, что в Питоне нельзя кильнуть тред? Если у тебя тред повиснет на каком-то блокирующем вызове, то только либо ждать, либо мочить весь процесс. Причина такого поведения в том, что сигналы в Питоне обрабатывает только основной процесс, даже если ты их шлёшь в конкретный тред, а если в основном процессе замаскировать сигнал, то он вообще никуда не дойдёт. И, получается, в функции pthread_kill() — никакого смысла.

Такие, вот, дела. Я не знал. По ссылке есть пара интересных способов завершить тред: https://www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/

Ну, вдруг вы тоже не знали, а теперь знаете.

anonymous
()
Ответ на: комментарий от anonymous

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

Aswed ★★★★★
()
Ответ на: комментарий от anonymous

Класс, а если память внутри треда аллоцируется в куче через shared_ptr какой-нибудь или даже через new, это же c++ почему бы и нет, что будет с этой памятью после вызова request_stop?

Aswed ★★★★★
()
Ответ на: комментарий от Aswed

Ну вообще «килять тред» это в любом ЯП плохая идея.

Так даже если просто другой сигнал слать, то тоже бессмысленно.

anonymous
()

Хочется иметь к ним какое-то CLI или API чтобы дёргать внутренние функции.

если делать по хардкору, то существует вот такая вот фигня

https://pypi.org/project/remote-pdb/

ставишь в коде брейкпойнт, потому подключаешься к нему удалённым отладчиком

дальше можно менять глобальные переменные и дергать функции какие угодно, всё как в обычном ipdb

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.