ruby MS windows gem: win32 / daemon: поток Service_Main вышел ненормально - PullRequest
2 голосов
/ 05 февраля 2020

Я пишу сценарий ruby для отправки файлов на сервер, как только они будут добавлены в папку.

Этот сценарий необходимо запустить в качестве службы на компьютере MS windows и использует win32/daemon gem, чтобы сделать его сервисом. Но я не могу запустить скрипт.

Имя файла check.rb, и при запуске ruby check.rb через cmd (от имени администратора) на Windows я получаю эта ошибка:

Поток Service_Main аварийно завершился

Вот некоторые снимки экрана сценария запуска и полученная ошибка:

enter image description here

error which I get

Вот файл кода:

require 'rubygems'
require 'win32/daemon'
require "csv"
require "rest_client"
require "colorize"
require 'logger'

include Win32

def working_dir
  # '/home/manav/Desktop/work/tripbeam'
  'C:\\AIR'
end

def sub_dir_seperator
  # '/'
  '\\'
end

$log = Logger.new(working_dir + sub_dir_seperator + 'logs.txt')

def print_it(message)
  puts message
  $log.debug(message)
end

def get_files
  begin
      Dir.entries(working_dir).select { |f| !File.directory? f }.select { |f| f =~ /AIR\d{5}.Txt/  }.sort_by{|f| File.ctime(working_dir + sub_dir_seperator + f)}
  rescue Exception => e
      print_it "Error getting files in directory: #{working_dir}"
      print_it "Err class #{e.class}, message: #{e.message}"
  end
end

def add_record_to_csv_with_fail(filename)
  begin
    print_it "Adding #{filename} to records.csv"
    CSV.open(working_dir + sub_dir_seperator + "records.csv", "a") do |csv|
        created_time = File.ctime(working_dir + sub_dir_seperator + filename).to_s
        csv << [filename, created_time, "", "fail"]
    end
    print_it "Added #{filename} to records.csv with status fail"
  rescue => e
    print_it "Error adding #{filename} to records.csv"
    print_it "Err class #{e.class}, message: #{e.message}"
  end
end

def add_record_to_csv_with_success(filename)
  begin
    print_it "Adding #{filename} to records.csv"
    CSV.open(working_dir + sub_dir_seperator + "records.csv", "a") do |csv|
        created_time = File.ctime(working_dir + sub_dir_seperator + filename).to_s
        csv << [filename, created_time, "", "success"]
    end
    print_it "Added #{filename} to records.csv with success"
  rescue => e
    print_it "Error adding #{filename} to records.csv"
    print_it "Err class #{e.class}, message: #{e.message}"
  end
end

def send_file_to_server(url, params, headers, filename)
    print_it "sending #{filename} to server..."
    begin
        response = RestClient.post(url, params, headers)
        responsebody = eval(response.body)
    print_it "Response from Server: " + responsebody[:message]
    if responsebody[:message].eql?("Success")
      print_it "Sent file to server"
      add_record_to_csv_with_success(filename)
    else
      add_record_to_csv_with_fail(filename)
    end
    rescue Exception => e
        print_it "Can not send the file to server"
    print_it "Err class #{e.class}, message: #{e.message}"
    add_record_to_csv_with_fail(filename)
  ensure
    $number_of_files += 1
    end
end

def api_url
    'https://tripbeam.us/api/v1/files'
    # 'http://192.168.1.18:3002/api/v1/files'
end

def delete_files_from_records
  current_files = get_files
  records = CSV.read(working_dir + sub_dir_seperator + "records.csv", headers:true)
  print_it "Updating records.csv"
  records.each do |row|
      if !(current_files.include? row['name'])
          #update delete column
          row['deleted'] = Time.now.to_s
      end
  end

  #save record
  CSV.open(working_dir + sub_dir_seperator + "records.csv", "w") do |csv_out|
      csv_out << ["name", "created", "deleted", "sent_status"]
      records.each do |row|
          csv_out << row
      end
  end

  print_it "Updated records.csv"

  $number_of_files = get_files.length

end

def add_files_added_while_program_not_running
  current_files = get_files

  records = CSV.read(working_dir + sub_dir_seperator + 'records.csv', headers:true)

  recorded_files = records.by_col[0]

  added_files = current_files - recorded_files

  if added_files.length != 0
      print_it "#{added_files.length} file(s) were added while the program was shut down."
  end

  added_files.each do |added_file|
      file_to_send = File.new(working_dir + sub_dir_seperator + added_file)
      params = {:attachment => file_to_send}
      headers = {:"Accept" => 'application/vnd.tripbeam.v1'}
      send_file_to_server(api_url, params, headers, added_file)
  end

end

begin
    class DemoDaemon < Daemon

    def service_init
      print_it "Initializing background service..."
      10.times{ |i|
        print_it i.to_s
        sleep 1
      }
      print_it "Initialized background service..."
    end

    def service_main(*args)
      #before listen
      $number_of_files = get_files.length
      current_files = get_files
      records = CSV.read(working_dir + sub_dir_seperator + 'records.csv', headers:true)
      recorded_files_names = records.by_col[0]

      #check which files were added aftrt program shut down
      add_files_added_while_program_not_running()

      #Listen for new files
      $number_of_files = get_files.length

      print_it "Number of files in dir: #{working_dir} : #{$number_of_files}"

      # While we're in here the daemon is running.
      while running?
        if state == RUNNING
          #listen here....
          while true
            begin
              sleep(1)
              current_files = get_files

              if $number_of_files > current_files.length
                #file deleted
                number_of_files_deleted = $number_of_files - current_files.length
                print_it "#{number_of_files_deleted} file(s) deleted"

                #update records.csv
                delete_files_from_records

              elsif $number_of_files < current_files.length
                #file added
                number_of_files_added = current_files.length - $number_of_files
                print_it "#{number_of_files_added} file(s) added"

                #send to server
                files_added = current_files[($number_of_files - current_files.length)..current_files.length]

                files_added.each do |added_file|
                    file_to_send = File.new(working_dir + sub_dir_seperator + added_file)
                    params = {:attachment => file_to_send}
                    headers = {:"Accept" => 'application/vnd.tripbeam.v1'}
                    send_file_to_server(api_url, params, headers, added_file)
                end
              end
            rescue Exception => e
              print_it "Error while listening, #{e.class}, message: #{e.message}"
            end
          end

        else # PAUSED or IDLE
          print_it "Somebody has paused the service..."
          sleep 100
        end
      end

      msg = 'service_main left at: ' + Time.now.to_s
      print_it msg
    end

    def service_stop
      msg = 'Received stop signal at: ' + Time.now.to_s
      print_it msg
    end

    # This event triggers when the service receives a signal to pause.
    #
    def service_pause
      msg = 'Received pause signal at: ' + Time.now.to_s
      print_it msg
    end

    # This event triggers when the service receives a signal to resume
    # from a paused state.
    #
    def service_resume
      msg = 'Received resume signal at: ' + Time.now.to_s
      print_it msg
    end
  end

  # Create an instance of the Daemon and put it into a loop. I borrowed the
  # method name 'mainloop' from Tk, btw.
  #
  DemoDaemon.mainloop
rescue Exception => err
  print_it "service failure: #{err.class} .... #{err.message}"
  raise
end

1 Ответ

0 голосов
/ 14 февраля 2020

Я пишу ruby скрипт для отправки файлов на сервер, как только они будут добавлены в папку.

Прежде всего, al oop в вашем коде (в методе service_main) перечитывает диск каждую секунду, 24/7. (Это весь день и всю ночь - и по выходным тоже!) Это быстро и неожиданно изнашивает диск вашего клиента. : (

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

Вы можете искать следующее:

directory notification windows ruby

Это дает (например) программу WatchDirectory , которую можно запустить как Windows службу .

Лучше использовать готовую программу, потому что ваша команда будет иметь меньше кода для обслуживания.

WatchDirectory может вызывать пользовательский пакетный файл всякий раз, когда что-либо изменяется в целевом каталоге. «Существует также специальный плагин, который может запускать скрипт файла .bat, что дает вам 100% гибкость.» Таким образом, пакетный файл может запустить программу Ruby (которую вы можете написать). Программа Ruby может сравнивать каталог содержимого и выполнения любой другой желаемой функциональности.

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

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

В качестве альтернативы использованию WatchDirectory вы можете выполнить поиск в Интернете по следующему адресу:

watchdirectory alternatives

One Результатом является страница на сайте AlternativeTo: Альтернативы WatchDirectory (для Windows).

Если вы предпочитаете написать собственный код (создание многоязычного решения с Ruby и немного C ++, вместо использования готовой программы, такой как WatchDirectory), ссылка на некоторый полезный образец кода C ++ от Microsoft (который отслеживает папки) также появилась в результате первого упомянутого мной веб-поиска выше.

Машина MS windows используется многими людьми, поэтому мы не хотим, чтобы кто-либо по ошибке закрывал терминал cmd.

Если вы wi sh для любой (не Windows сервисной) программы, которая всегда скрыта от панели задач (по любой причине), вы можете выполнить веб-поиск следующим образом:

windows program hide

Один результат - Best Ways быстро скрыть приложение Windows s , что дает настраиваемые и, по-видимому, полезные "Windows Hide Tool" и "ClickyGone."

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...