При работе с Rails мы постоянно пользуемся rake-задачами. Я, например, стараюсь вообще все процессы обработки данных, которые обычно выносят в миграции, выносить в виде отдельных rake-задач вида app:maintenance:*. Это очень удобно при разработке, так как позволяет запускать задачи независимо от миграций. А в миграциях задачи можно просто вызывать вот таким образом:

Ruby Code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class MyMigration < ActiveRecord::Migration
  def self.up
    # ... DB Schema modifications ...

    Rake::Task["app:maintenance:my_migration:up"].execute

    # ... DB Schema modifications ...
  end

  def self.down
    # ... DB Schema modifications ...

    Rake::Task["app:maintenance:my_migration:down"].execute

    # ... DB Schema modifications ...
  end
end

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

По ходу копания в иходниках gem’а rake я выяснил неприятную вещь – никаких средств для разширения в нем на данный момент не предусмотрено. В irb, например, можно добавлять расширения через файл .irbrc. С rake такой номер не пройдет. Поэтому есть два пути – расширять функционал и делать собственный форк, либо перекрывать существующий функционал. Я выбрал второй путь как наименее трудозатратный (хоть это и не труъ).

Итак, для того, чтобы добавить уведомления, нам нужно сделать собственный исполняемый файл rake. Изначально я хотел просто положить его в ~/.bash/rake, но обнаружил, что RVM прописывает свои пути перед всеми ранее заданными, то есть стандарнтый исполняемый файл rake выполняется в первую очередь. Поэтому я добавил новую запись в ~/.bash_aliases:

Bash Code
1
alias rake='~/.bash/rake.rb'

Теперь при вызове команды rake будет вызываться мой ruby-файл. Сам файл я сделал исполняемым:

Bash Code
1
chmod +x ~/.bash/rake.rb

Сам код файла таков:

Ruby Code
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/usr/bin/env ruby

begin
  require 'rake'
rescue LoadError
  require 'rubygems'
  require 'rake'
end

class Rake::Application
  def task_list
    top_level_tasks.join(' ')
  end

  def notify(message, body, urgency, icon = :info)
    system("notify-send --urgency=#{urgency} --icon=#{icon} '#{message}' '#{body}'")
  end

  def after_run
    notify('Rake Tasks: Finished', task_list, :low) unless task_list == 'default'
  end

  def after_fail
    notify('Rake Tasks: Failed', task_list, :normal, :error)
  end

  def top_level_with_callbacks
    top_level_without_callbacks

    after_run
  end

  alias_method :top_level_without_callbacks, :top_level
  alias_method :top_level, :top_level_with_callbacks

  def run_with_callbacks
    begin
      run_without_callbacks
    rescue SystemExit => e
      after_fail

      exit(falses)
    end
  end

  alias_method :run_without_callbacks, :run
  alias_method :run, :run_with_callbacks
end

Rake.application.run

Так как я работаю под Ubuntu, то уведомления я отправляю через notify-send. Вариантов уведомлений два – при успешном выполнении и при ошибке. Единственное, чего мне пока что не удалось добиться – это регулирования времени отображения уведомлений. Но этот момент целиком обусловлен особенностями дизайна убунтовского NotifyOSD, который игнорирует переданное время жизни уведомления.

Эффект от этого маленького трюка у меня выглядит вот так:

rake notes

rake three undefined tasks

Теперь для полного счастья теперь нужно сделать уведомления для Capistrano :) Если знаете какой-нибудь готовый плагин – дайте знать.