• Crontab и отправка почты

    На днях столкнулся с проблемой. На моем ноуте крутится несколько crontab-задач. Хотелось бы видеть, когда сработала каждая из них и если нет, то почему. Какое-то время я выкручивался с помощью логов. Оба канала (stdout и stderr) перехватываются в общий пайп, где каждая строка предваряется текущий датой и записывается в файл. Например:

    SHELL=/bin/bash
    
    0 */3 * * * /path/to/command &> >( while read line; do echo "$(date): ${line}"; done >> /Users/ivan/logs/command.log)
    

    В результате и обычный, и ошибочный выхлоп оседают в файле. Выглядит это так:

    Tue Jun 22 15:58:02 MSK 2021: warning: Skipping file ...
    Tue Jun 22 15:58:19 MSK 2021: Completed 0 file(s) with ...
    Tue Jun 22 15:59:02 MSK 2021: warning: Skipping file /Users/ivan/...
    Tue Jun 22 15:59:19 MSK 2021: Completed 0 file(s) with ...
    

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

    Тут я вспомнил, что крон умеет отправлять выхлоп задачи на почту. Если задана переменная MAILTO=<email>, то на эту почту свалится выхлоп. Это значит, отпадают логи, ведь теперь достаточно проверить почту. Проверять ее можно и с телефона, что в разы удобней.

    Отправка письма работает за счет утилиты mail. В общем виде ей пользуются так:

    cat something | mail -s 'subject' friend@domain.com
    

    Эта команда отправит письмо на сервер domain.com, при этом отправитель будет выглядеть как ivan@ivan.local, то есть имя пользователя и текущего хоста. То же самое можно получить командой:

    echo `whoami`@`hostname`
    

    Обратите внимание на кавычки – они означают выполнить выражение в новом шелле и подставить результат.

    Отправленное письмо никто не получит, что потому что современные сервера отметают письма, где айпи отправителя не совпадает с айпи его домена. Это хорошо, иначе бы мы утонули в спаме. Будем отправлять письма с серверов Гугла. А чтобы mail мог подключиться к Гуглу, сделаем три вещи.

    Первое. В файл /etc/postfix/main.cf дописать строки ниже. Делать это нужно под sudo:

    relayhost = [smtp.gmail.com]:587
    smtp_sasl_auth_enable = yes
    smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
    smtp_sasl_security_options = noanonymous
    smtp_use_tls = yes
    smtp_sasl_mechanism_filter = plain
    

    Второе. Создать файл /etc/postfix/sasl_passwd и вписать в него:

    [smtp.gmail.com]:587 username@gmail.com:password
    

    , где password — пароль приложения для почты. Сгенерить этот пароль можно на специальной странице Гугла.

    Замечу, что вместо gmail.com может быть ваш домен, если он нацелен на гугловые сервера как в моем случае.

    Третье — указать postfix новые конфиги и перезагрузить его:

    sudo chmod 600 /etc/postfix/sasl_passwd
    sudo postmap /etc/postfix/sasl_passwd
    sudo launchctl stop org.postfix.master
    sudo launchctl start org.postfix.master
    

    Все. Пробуем отправить письмо. Сообщим в нем содержимое домашней папки:

    ls -l | mail -s 'my home dir' ivan@grishaev.me
    

    Мне пришло с первого раза. Plain text, красота.

    Так вот, теперь когда почта работает, настроим крон. Открываем его командой crontab -e и пишем сверху:

    MAILTO=<ваша@почта>
    

    Кроме того, в конец каждой команды добавляем эхо, например:

    0 */3 * * * cd /some/path && command --foo 42 && echo OK
    

    Зачем нужно эхо? Оказалось, что крон не отправляет письмо, если выхлоп задачи пуст. А поскольку я всегда хочу знать о запуске задачи, то делаю вывод не пустым. Вместо echo OK можно вывести текущую дату с помощью && date.

    В результате мы получим письмо, где тема — команда задачи, а тело — ее выхлоп. Работает в том числе и для задач, которые не сработали из-за ошибки.

    Я уж не говорю о том, что с помощью mail можно быстро что-то скидывать себе на почту, организовать какие-то заметки и прочее. Что самое прекрасное — нет интерфейса, все простое и открытое, работает везде. Чудо.

    В следующий раз расскажу, что именно я ставлю на крон, там тоже интересные вещи.

  • И ещё немного книг

    Выкладываю ещё несколько прочитанных книжек. Полную подборку см. на книжной полке.

    Чернобыль. История катастрофы
    Хиггинботам Адам

    Полная история чернобыльских событий. Начинается задолго до взрыва, охватывает становление Припяти и ранние опыты с атомной энергией в СССР. Подробно описаны причины, которые привели к взрыву, в том числе организационные. Центральные персонажи показаны правдиво и без тех прикрас, что были в сериале HBO. Книга заканчивается развалом СССР и эпилогом. Рекомендую к прочтению.

    Digital минимализм. Как навести порядок в цифровой среде
    Рыжина Анастасия

    Книга о том, как навести порядок в файлах: на локальном компе и в облачных хранилищах. Довольно занятно, но затянуто. Проблема в том, что материал тянет на хорошую статью, но никак не на книгу. Отсюда дешёвые способы выйти на объём: мудрые цитаты на разворот, письма читателей и прочий балласт. Но пробежаться стоит.

    Думай как математик. Как решать любые задачи быстрее и эффективнее
    Барбара Оакли

    Автор — женщина-учёный, служила в армии США, преподавала в университете. В книге она описывает приемы эффективного обучения. Например, заниматься понемногу, но регулярно; не подчеркивать в книгах; мысленно пересказывать материал. Полезно, но затянуто. Я бы сократил книгу на треть.

    Структуры данных и алгоритмы в Java Лафоре Роберт
    Лафоре Роберт

    Прекрасная книга об алгоритмах. Столь понятного изложения я уже давно не встречал. Все алгоритмы показаны картинками и схемами; к каждому прилагается программа с интерфейсом для визуализации. Первая часть книги посвящена сортировке, вторая — деревьям. Все примеры на Java версии 1.3. Пусть это вас не пугает: никаких классов, всё на примитивах и массивах. Горячо рекомендую книгу всем, кто хочет разобраться с коллекциями и алгоритмами.

    Уступите место драме. Как писать интересно даже на скучные темы
    Сарычева Людмила

    Книга о драматургии Люды Сарычевой, соавтора "Пиши, сокращай". Не думайте, что драматургия — это обязательно Шекспир и все умирают. Речь о том, как сделать текст интересней с помощью персонажей и конфликтов, как обострять акценты и чередовать ритм. Прочитал половину: начало интересное и пригодится всем, а дальше уже только для специалистов в теме.

    Ходячий замок
    Джонс Диана Уинн

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

    Искусство войны
    Сунь-Цзы

    Тот самый трактат о войне, написанный две с половиной тысячи лет назад. Оригинал довольно короткий, буквально дюжина керамических табличек. Поэтому современные издания напичканы комментариями толкователей всех мастей. Это весьма раздражает: после каждой фразы оригинала следуют пять абзацев комментариев. К самому трактату претензий нет: он точен, ясен, в нём нет лишних деталей, он несет много пищи для размышления. Удивительно, что человек, который занимался войной, так много пишет о милосердии и заботе о людях.

  • Introducing Farseer: the JSON RPC server, the client and utilities

    (This is a copy of the readme file from the repository.)

    Farseer is a set of modules for JSON RPC. It includes a transport-independent handler, Ring HTTP handler, Jetty server, HTTP client, local stub, documentation, and more.

    What and Why is JSON RPC?

    Briefly, JSON RPC is a protocol based on HTTP & JSON. When calling the server, you specify the method (procedure) name and its parameters. The parameters could be either a map or a vector. The server returns a JSON response with the result or error fields. For example:

    Request:

    {"jsonrpc": "2.0", "method": "sum", "params": [1, 2], "id": 3}
    

    Response:

    {"jsonrpc": "2.0", "result": 3, "id": 3}
    

    Pay attention: the protocol depends on neither HTTP method, nor query params, nor HTTP headers and so on. Although looking a bit primitive, this schema eventually appears to be robust, scalable and reliable.

    Read more →

  • Сага о DRY и зависимостях

    Предположим, в вашем проекте два модуля: project.foo и project.bar. В первый из них вы добавили служебную функцию, например поиск элемента по предикату. Через некоторое время то же самое понадобилось во втором модуле. Как вы поступите?

    Варианты:

    1. Вынесу функцию в третий модуль project.utils и подключу его к foo и bar.
    2. Скопирую функцию во второй модуль.

    Конечно, вы и так знаете, что правильный способ — первый. DRY (Don’t Repeat Yourself), не дублируй код. Держи одну точку входа, чтобы в случае ошибки править в одном месте. Копирование — наш враг и все такое. Я тоже тоже так думал раньше, и вот, в тридцать пять лет, поменял мнение.

    Read more →

  • Clojure Zippers

    Part 1. The Basics of Navigation

    In this article, we will discuss zippers in the Clojure language. These are an unusual way to work with collections. Using a zipper, you can traverse a data structure arbitrarily and modify its content as well as search in it. A zipper is a powerful abstraction that pays off over time. However, it is not as straightforward as regular tools and requires training to deal with.

    Let’s talk about a zipper in simple terms. It is a wrapper that offers a variety of data manipulations. Let’s list the main ones:

    • moving vertically: down to children or up to a parent;
    • moving horizontally: left or right among children;
    • traversal of the entire data structure;
    • adding, editing and deleting nodes.

    Read more →

  • Ссылки на выходные (выпуск 34)

    Советую посвятить выходные новому изданию “Кинжал”. Ребята пишут небольшие заметки о работе и жизни. Получается супер. Каждая заметка — острая и хлесткая, как настоящий кинжал. Никакой воды, только по сути. Эти вещи вы читали у других и у меня, но в “Кинжале” написано лучше.

    То, что зацепило:

    И так далее, на сайте еще.

    А вот Максим Ильяхов (он там редачит) рассказывает об издании.

  • Configuration in Clojure

    Clojure in Production

    In This Chapter

    Configuration

    In this chapter, we will discuss how to make a Clojure project easy to configure. We’ll take a look at the basics of config: file formats, environment variables, libraries, and their pros and cons.

    Formulation of the Problem

    In materials on Clojure, there are such examples:

    (def server
      (jetty/run-jetty app {:port 8080}))
    
    (def db {:dbtype   "postgres"
             :dbname   "test"
             :user     "ivan"
             :password "test"})
    

    These are the server on port 8080 and the parameters for connecting to the database. The examples are useful because you can execute them in the REPL and check their result: open a page in a browser or perform a SQL query.

    In practice, we should write code so that it does not carry concrete numbers and strings. Explicitly setting a port number to a server is considered bad practice. That is fine for documentation and examples, but not for the production launch.

    Port 8080 and other combinations of zeros and eights are popular with programmers. There is a good chance that the port is occupied by another server. This happens when instead of running one service, you start a bunch of them at once during development or testing.

    The code written by a programmer goes through several stages. These stages may differ between companies, but in general, they are development, testing, staging/pre-production, and production.

    At each stage, the application runs alongside other projects. The assumption that port 8080 is free anytime is fanciful. In developer slang, the situation is called “hardcode” or “nailed down.” If there are nailed-down values in the code, they introduce problems into its life cycle. You cannot run two projects in parallel which declare port 8080 in their code.

    The application does not need to know the server port – information about this comes from the outside. In a simple case, this source is the config file. The program reads the port from it and starts the server exactly as it needs to do on a specific machine.

    In more complex scenarios, the file is not compiled by a person but a special program – a configuration manager. The manager stores information about network topology, machine addresses, and database access parameters. On request, it generate a config file for a specific machine or network segment.

    The process of passing parameters to an application and accepting them is called configuration. This step in software development deserves close attention. When it is done well, the project easily goes through all the stages of production.

    Read more →

  • Можно ударить по голове

    Недавно я употребил в блоге фразу: если не выстрелит, ей можно ударить по голове (речь о втором издании книги). Это отсылка к фильму Snatch, в русском переводе “Большой куш”. Вспомнил, как мы с приятелем будучи подростками смотрели гоблинский перевод и ржали над матами. А ещё вспомнил, что даже тогда заметил одну деталь, связанную с этой фразой.

    Напомню, её несколько раз произносит торговец оружием Борис. Он толкает покупателям откровенный хлам. Покупатель взвешивает оружие и замечает — что-то тяжеловато. На что Борис отвечает: тяжесть — это надёжность. Если не выстрелит, им можно ударить по голове.

    Фраза звучит несколько раз, и очевидно, в какой-то момент она должна сыграть. Поскольку мы в комедии, нелепый тезис должен сработать при нелепых обстоятельствах. Другими словами, повторяя некую фразу, режиссер подводит зрителя к ситуации. И тут нас ждёт разочарование — в случае “не выстрелит” режиссер не уделил шутке внимания.

    Томми, партнер главного героя, покупает нерабочий пистолет. Позже он испытывает его из окна машины, и оружие дает осечку. Но в момент, когда Турецкого готовы убить, Томми наставляет пистолет на бандитов и тем спасает Турецкого. Таким образом выполняется только первая часть шутки — не выстрелит.

    Ещё подростком я понял, что надо было обыграть фразу по-другому. Во-первых, когда Турецкий предлагает выстрелить из машины, Томми должен был отказаться. Якобы потому, что Борис — надёжный продавец как и его товар, поэтому сомневаться нет смысла. На самом деле Томми боится оружия, и это только бы усилило ожидание шутки.

    Когда на Турецкого нападают бандиты, один из них душит его. Томми пытается выстрелить, но пистолет не работает. В глазах Турецкого ужас — пропала последняя надежда, ведь на физические способности Томми рассчитывать не приходится. Томми мечется, его взгляд падает на нерабочий пистолет. Он вспоминает напутствие продавца, берет пистолет за ствол и бьет бандита по голове. Тот сползает с Турецкого. Оба героя переводят дух, молча смотрят на оружие и кивают. В их глазах проскальзывает “действительно, им можно ударить по голове”.

    Так сбывается нелепое пророчество. В этом варианте раскрыты обе части шутки, и согласитесь, это было бы смешнее (в рамках криминальной комедии). Конечно, на словах звучит слегка коряво, но режиссёр на то и нужен, чтобы всё это обыграть камерой, мимикой, диалогами.

    Морали нет, просто наблюдение. Уже давно замечаю за собой, что после фильма обдумываю отдельные сцены, чтобы найти более удачные повороты сюжета, диалоги или черты персонажей. Эта заметка — попытка зафиксировать одну из таких идей.

  • Переназначение клавиш на Маке

    В этой статье я бы хотел поговорить об изменении клавиш на клавиатуре. Сперва это была короткая заметка, но со временем текст вырос во что-то большее. Оказалось, есть что сказать по теме.

    Вообще, я не стремлюсь менять клавиши и затачивать программы под себя. Разработчики предлагают удобные схемы, и в целом удобно, когда вы работаете на стандартных настройках. Всё же, годы за клавиатурой подталкивают к некоторым изменениям.

    Главный довод в пользу изменения клавиш — физиология. У людей разная форма кистей и длина пальцев. Невозможно выпустить клавиатуру, которая подошла бы всем людям. Именно физиология и чуткое внимание к ощущениям подсказывают, что менять что-то нужно, иначе — боль в суставах.

    Одно время я увлекался эргономичными клавиатурами, но быстро разочаровался в них. За огромные деньги мы получим поделие Франкенштейна: огромных размеров, тяжелое, неудобное. Такая клавиатура полностью меняет рабочее пространство, заставляет кое-что купить в довесок. Её не возьмешь в командировку или на дачу, словом — нет.

    Типичные пациенты:

    На последней картинке – Microsoft Sculpt. Я пользовался ей полгода, но страшно заболела левая рука.

    Read more →

  • Что не так

    Один из самых дурацких вопросов — “что не так с X”. Примеры:

    • Мы в редакции не используем букву ё.
    • Что не так с ё?

    • Мы перешли с Node.js на Python.
    • Что не так с Нодой?

    • Новый ролик я монтировал в Final Cut, а не Premiere.
    • Что не так с Премьером?

    Беда вот в чём. Ни одно из утверждений не говорит о том, что с буквой ё, программой или языком что-то не так. От них отказались по каким-то причинам, а с самим предметом всё в порядке. Поэтому вопрос задан неправильно — следовало спросить, почему вы решили; почему отказались; что вынудило и так далее.

    Но собеседник переложил работу на меня. Я понимаю, что он имел в виду, но тогда мой ответ звучит слабо. С буквой ё все в порядке, просто мы…, программа хорошая, но я… Получается ерунда.

    Заметил, что подобный вопросы задают тролли, которым нужна подобная интонация. Либо человек, которым движет вера. Что бы вы ни сказали, он будет гнуть свою линию. Отсюда эта лёгкая дерзость: во фразе “что не так с X” уже слышится претензия.

    Подобные вещи я либо игнорирую, либо прошу задать вопрос правильно. Что ты имеешь в виду? Я не говорил, что с X что-то не так. Объясни, чего хочешь.

    Кидайте эту заметку тем, кто злоупотребляет “что не так с X”.

    См. также Whataboutism.

Страница 44 из 96