feedupdater 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG CHANGED
@@ -1,2 +1,5 @@
1
+ == FeedUpdater 0.2.0
2
+ * multithreaded
3
+ * unchanged feeds will no longer call on_update
1
4
  == FeedUpdater 0.1.0
2
5
  * initial version
@@ -5,8 +5,15 @@ start_delay: false
5
5
  # See the documentation for details.
6
6
  load_script: example/custom_updater.rb
7
7
 
8
+ # Keep this set to 1 unless you're certain you need to set it higher.
9
+ # Never set it higher than 1 if you're on a shared server.
10
+ threads: 5
11
+
8
12
  # This is the path to store the pid files.
9
13
  pid_file_path: config
10
14
 
11
15
  # This is the path to store the log files.
12
16
  log_file_path: log
17
+
18
+ # Log level
19
+ log_level: 0
@@ -1,7 +1,7 @@
1
1
  module FeedTools
2
2
  module FEED_UPDATER_VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 1
4
+ MINOR = 2
5
5
  TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
data/lib/feed_updater.rb CHANGED
@@ -55,6 +55,41 @@ if !defined?(FeedTools::FEED_TOOLS_VERSION)
55
55
  end
56
56
 
57
57
  require 'benchmark'
58
+ require 'thread'
59
+ require 'logger'
60
+
61
+ class FeedUpdaterLogger < Logger
62
+ attr_accessor :prefix
63
+
64
+ alias_method :old_log, :log
65
+ def log(level, message)
66
+ if defined?(@prefix) && @prefix != nil
67
+ self.old_log(level, self.prefix + message)
68
+ else
69
+ self.old_log(level, message)
70
+ end
71
+ end
72
+
73
+ def debug(message)
74
+ self.log(0, message)
75
+ end
76
+
77
+ def info(message)
78
+ self.log(1, message)
79
+ end
80
+
81
+ def warn(message)
82
+ self.log(2, message)
83
+ end
84
+
85
+ def error(message)
86
+ self.log(3, message)
87
+ end
88
+
89
+ def fatal(message)
90
+ self.log(4, message)
91
+ end
92
+ end
58
93
 
59
94
  module FeedTools
60
95
  # A simple daemon for scheduled updating of feeds.
@@ -127,7 +162,11 @@ module FeedTools
127
162
  # Returns the logger object.
128
163
  def logger()
129
164
  if !defined?(@logger) || @logger.nil?
130
- @logger = Logger.new(self.log_file)
165
+ @logger = FeedUpdaterLogger.new(self.log_file)
166
+ @logger.level = self.updater_options[:log_level]
167
+ @logger.datetime_format = nil
168
+ @logger.progname = nil
169
+ @logger.prefix = "FeedUpdater".ljust(20)
131
170
  end
132
171
  return @logger
133
172
  end
@@ -139,7 +178,11 @@ module FeedTools
139
178
  self.logger.close()
140
179
  rescue IOError
141
180
  end
142
- @logger = Logger.new(self.log_file)
181
+ @logger = FeedUpdaterLogger.new(self.log_file)
182
+ @logger.level = self.updater_options[:log_level]
183
+ @logger.datetime_format = nil
184
+ @logger.progname = nil
185
+ @logger.prefix = "FeedUpdater".ljust(20)
143
186
  end
144
187
 
145
188
  # Returns a list of feeds to be updated.
@@ -174,7 +217,9 @@ module FeedTools
174
217
  def updater_options()
175
218
  if !defined?(@updater_options) || @updater_options.nil?
176
219
  @updater_options = {
177
- :start_delay => true
220
+ :start_delay => true,
221
+ :thread => 1,
222
+ :log_level => 0
178
223
  }
179
224
  end
180
225
  return @updater_options
@@ -234,6 +279,7 @@ module FeedTools
234
279
 
235
280
  # Starts the daemon.
236
281
  def start()
282
+ self.logger.prefix = "FeedUpdater".ljust(20)
237
283
  if !defined?(@@on_update) || @@on_update.nil?
238
284
  raise "No on_update handler block given."
239
285
  end
@@ -241,6 +287,9 @@ module FeedTools
241
287
  puts "FeedUpdater is already running."
242
288
  return self.pid
243
289
  end
290
+ if defined?(ActiveRecord)
291
+ ActiveRecord::Base.allow_concurrency = true
292
+ end
244
293
 
245
294
  @initial_directory = File.expand_path(".")
246
295
 
@@ -280,9 +329,13 @@ module FeedTools
280
329
  self.update_feeds()
281
330
  end
282
331
  self.logger.info(
283
- "#{@feed_href_list.size} feeds updated " +
332
+ "#{@feed_href_list.size} feed(s) updated " +
284
333
  "in #{result.real.round} seconds.")
285
- ObjectSpace.garbage_collect
334
+ if !defined?(@feed_href_list_override) ||
335
+ !@feed_href_list_override
336
+ @feed_href_list = nil
337
+ end
338
+ ObjectSpace.garbage_collect()
286
339
  sleepy_time = 1.hour - result.real.round
287
340
  if sleepy_time > 0
288
341
  self.logger.info(
@@ -304,11 +357,16 @@ module FeedTools
304
357
  else
305
358
  @application.start()
306
359
  end
360
+ self.logger.prefix = nil
361
+ self.logger.level = 0
307
362
  self.logger.info("-" * 79)
308
363
  self.logger.info("Daemon started, " +
309
364
  "FeedUpdater #{FeedTools::FEED_UPDATER_VERSION::STRING} / " +
310
365
  "FeedTools #{FeedTools::FEED_TOOLS_VERSION::STRING}")
311
366
  self.logger.info(" @ #{Time.now.utc.to_s}")
367
+ self.logger.info("-" * 79)
368
+ self.logger.level = self.updater_options[:log_level]
369
+ self.logger.prefix = "FeedUpdater".ljust(20)
312
370
  @status = :running
313
371
  return self.pid
314
372
  end
@@ -340,7 +398,10 @@ module FeedTools
340
398
  end
341
399
  rescue Exception
342
400
  end
401
+ self.logger.prefix = "FeedUpdater".ljust(20)
402
+ self.logger.level = 0
343
403
  self.logger.info("Daemon stopped.")
404
+ self.logger.level = self.updater_options[:log_level]
344
405
  @status = :stopped
345
406
  return nil if self.application.nil?
346
407
  begin
@@ -358,40 +419,170 @@ module FeedTools
358
419
 
359
420
  # Updates all of the feeds.
360
421
  def update_feeds()
422
+ self.logger.prefix = "FeedUpdater".ljust(20)
423
+ ObjectSpace.garbage_collect()
361
424
  if defined?(@feed_href_list_override) && @feed_href_list_override
362
425
  self.feed_href_list()
363
426
  else
427
+ self.logger.info("Loading default feed list...")
364
428
  @feed_href_list =
365
- FeedTools.feed_cache.find(:all).collect do |cache_object|
366
- cache_object.href
429
+ (FeedTools.feed_cache.find(:all).collect do |cache_object|
430
+ cache_object.href
431
+ end)
432
+ end
433
+ self.logger.info("Updating #{@feed_href_list.size} feed(s)...")
434
+ ObjectSpace.garbage_collect()
435
+
436
+ threads = []
437
+ thread_slices = []
438
+ thread_slice_size =
439
+ (@feed_href_list.size / self.updater_options[:threads])
440
+
441
+ for i in 0...self.updater_options[:threads]
442
+ if i != self.updater_options[:threads] - 1
443
+ thread_slices << @feed_href_list[
444
+ (i * thread_slice_size)...((i + 1) * thread_slice_size)]
445
+ else
446
+ thread_slices << @feed_href_list[
447
+ (i * thread_slice_size)..-1]
367
448
  end
368
449
  end
369
- self.logger.info("Updating #{@feed_href_list.size} feeds...")
370
- for href in @feed_href_list
371
- begin
372
- begin
373
- feed = nil
374
- feed_load_benchmark = Benchmark.measure do
375
- feed = FeedTools::Feed.open(href)
376
- end
377
- unless @@on_update.nil?
378
- self.cloaker(&(@@on_update)).bind(self).call(
379
- feed, feed_load_benchmark.real)
380
- end
381
- rescue Exception => error
382
- if @@on_error != nil
383
- self.cloaker(&(@@on_error)).bind(self).call(href, error)
384
- else
385
- self.logger.info("Error updating '#{href}':")
450
+ ObjectSpace.garbage_collect()
451
+
452
+ begin_updating = false
453
+ self.logger.info(
454
+ "Starting up #{self.updater_options[:threads]} thread(s)...")
455
+
456
+ mutex = Mutex.new
457
+ for i in 0...self.updater_options[:threads]
458
+ updater_thread = Thread.new do
459
+ self.logger.level = self.updater_options[:log_level]
460
+ self.logger.datetime_format = "%s"
461
+ self.logger.progname = "FeedUpdater".ljust(20)
462
+
463
+ while !Thread.current.respond_to?(:thread_id) &&
464
+ begin_updating == false
465
+ Thread.pass
466
+ end
467
+ mutex.synchronize do
468
+ self.logger.prefix = "Thread #{Thread.current.thread_id} ".ljust(20)
469
+ self.logger.info("Thread started.")
470
+
471
+ begin
472
+ FeedTools.feed_cache.initialize_cache()
473
+ if !FeedTools.feed_cache.set_up_correctly?
474
+ self.logger.info("Problem with cache connection...")
475
+ end
476
+ rescue Exception => error
386
477
  self.logger.info(error)
387
478
  end
479
+
480
+ self.logger.info(
481
+ "Thread ##{Thread.current.thread_id} handling " +
482
+ "#{thread_slices[Thread.current.thread_id].size} feeds...")
388
483
  end
389
- rescue Exception => error
390
- self.logger.info("Critical unhandled error.")
391
- self.logger.info("Error updating '#{href}':")
392
- self.logger.info(error)
484
+
485
+ ObjectSpace.garbage_collect()
486
+ Thread.pass
487
+ href_list = thread_slices[Thread.current.thread_id]
488
+
489
+ for i in 0...href_list.size
490
+ href = nil
491
+ progress = nil
492
+ mutex.synchronize do
493
+ href = href_list[i]
494
+ Thread.current.progress =
495
+ (href_list.index(href).to_f / href_list.size.to_f) * 100
496
+ progress = sprintf("%.2f", Thread.current.progress)
497
+ end
498
+ begin
499
+ begin
500
+ feed = nil
501
+ feed_load_benchmark = Benchmark.measure do
502
+ feed = FeedTools::Feed.open(href)
503
+ end
504
+ Thread.pass
505
+ if feed.live?
506
+ unless @@on_update.nil?
507
+ mutex.synchronize do
508
+ progress = sprintf("%.2f", Thread.current.progress)
509
+ self.logger.prefix = ("Thread #{Thread.current.thread_id} " +
510
+ "(#{progress}%)"
511
+ ).ljust(20)
512
+ self.cloaker(&(@@on_update)).bind(self).call(
513
+ feed, feed_load_benchmark.real)
514
+ end
515
+ end
516
+ else
517
+ mutex.synchronize do
518
+ progress = sprintf("%.2f", Thread.current.progress)
519
+ self.logger.prefix = ("Thread #{Thread.current.thread_id} " +
520
+ "(#{progress}%)"
521
+ ).ljust(20)
522
+ self.logger.info(
523
+ "'#{href}' unchanged, skipping.")
524
+ end
525
+ end
526
+ rescue Exception => error
527
+ mutex.synchronize do
528
+ progress = sprintf("%.2f", Thread.current.progress)
529
+ self.logger.prefix = ("Thread #{Thread.current.thread_id} " +
530
+ "(#{progress}%)"
531
+ ).ljust(20)
532
+ if @@on_error != nil
533
+ self.cloaker(&(@@on_error)).bind(self).call(href, error)
534
+ else
535
+ self.logger.error("Error updating '#{href}':")
536
+ self.logger.error(error.class.name + ": " + error.message)
537
+ self.logger.error(error.class.backtrace)
538
+ end
539
+ end
540
+ end
541
+ rescue Exception => error
542
+ mutex.synchronize do
543
+ progress = sprintf("%.2f", Thread.current.progress)
544
+ self.logger.prefix = ("Thread #{Thread.current.thread_id} " +
545
+ "(#{progress}%)"
546
+ ).ljust(20)
547
+ self.logger.fatal("Critical unhandled error.")
548
+ self.logger.fatal("Error updating '#{href}':")
549
+ self.logger.fatal(error.class.name + ": " + error.message)
550
+ self.logger.fatal(error.class.backtrace)
551
+ end
552
+ end
553
+ ObjectSpace.garbage_collect()
554
+ Thread.pass
555
+ end
556
+ end
557
+ threads << updater_thread
558
+ class <<updater_thread
559
+ attr_accessor :thread_id
560
+ attr_accessor :progress
561
+ end
562
+ updater_thread.thread_id = i
563
+ end
564
+ mutex.synchronize do
565
+ self.logger.prefix = "FeedUpdater".ljust(20)
566
+ self.logger.info(
567
+ "#{threads.size} thread(s) successfully started...")
568
+ begin_updating = true
569
+ end
570
+ Thread.pass
571
+
572
+ ObjectSpace.garbage_collect()
573
+ Thread.pass
574
+ for i in 0...threads.size
575
+ mutex.synchronize do
576
+ self.logger.prefix = "FeedUpdater".ljust(20)
577
+ self.logger.info(
578
+ "Joining on thread #{threads[i].thread_id}...")
393
579
  end
580
+ threads[i].join
394
581
  end
582
+ self.logger.prefix = "FeedUpdater".ljust(20)
583
+ ObjectSpace.garbage_collect()
584
+
585
+ self.logger.progname = nil
395
586
  unless @@on_complete.nil?
396
587
  self.cloaker(&(@@on_complete)).bind(self).call(@feed_href_list)
397
588
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: feedupdater
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.1.0
7
- date: 2006-04-13 00:00:00 -07:00
6
+ version: 0.2.0
7
+ date: 2006-04-17 00:00:00 -07:00
8
8
  summary: Automatic feed updater daemon.
9
9
  require_paths:
10
10
  - lib
@@ -32,7 +32,6 @@ files:
32
32
  - bin
33
33
  - CHANGELOG
34
34
  - config
35
- - doc
36
35
  - example
37
36
  - lib
38
37
  - log
@@ -55,7 +54,6 @@ files:
55
54
  - lib/feed_updater/vendor/daemons/pid.rb
56
55
  - lib/feed_updater/vendor/daemons/pidfile.rb
57
56
  - lib/feed_updater/vendor/daemons/pidmem.rb
58
- - config/feed_updater.pid
59
57
  - config/feed_updater.yml
60
58
  - example/custom_updater.rb
61
59
  test_files: []
@@ -1 +0,0 @@
1
- 617