出社して、さて前夜から溜った feed を読もうかな、と Plagger を走らせて。
未読 entry が 500 ほど溜った状態で
Can't use string ("500 Server closed connection wit") as a HASH ref while "strict refs" in
use at /home/fujiwara/devel/plagger/lib/Plagger/Plugin/Subscription/LivedoorReader.pm line 80.コケた。LDR のサーバがエラーを返したのに、それをデータとして処理しようとしたため。(リファレンスでないのをデリファレンスしようとした)
feed や entry を読み込んでメモリ上に乗っかった状態で (しかも LDR 側は既読にしちゃった後)、Store も Publish もする前に落ちると、未読が全部メモリの露と消える。悲しすぎる。
DB みたいにトランザクション処理、というのも難しいが、せめて少しでも被害を防ぐ patch.
diff の都合でやたらと長いけど、要は
my $feed = Plagger::Feed->new;
から
$context->update->add($feed);
までを eval で括って例外を捕捉。既読にする処理 ( touch_all ) は、そこまでの処理が正常に完了してから行うようにした。
Index: Subscription/LivedoorReader.pm
===================================================================
--- Subscription/LivedoorReader.pm (revision 1018)
+++ Subscription/LivedoorReader.pm (working copy)
@@ -72,39 +72,43 @@
for my $sub (@$subs) {
$context->log(debug => "get unread items of $sub->{subscribe_id}");
my $data = $self->_request("/api/unread", { subscribe_id => $sub->{subscribe_id} });
- $self->_request("/api/touch_all", { subscribe_id => $sub->{subscribe_id} })
- if $mark_read;
+ eval {
+ my $feed = Plagger::Feed->new;
+ $feed->type('livedoorReader');
+ $feed->title( Plagger::Util::strip_html($data->{channel}->{title}) );
+ $feed->link($data->{channel}->{link});
+ $feed->url($data->{channel}->{feedlink});
+ $feed->image({ url => $data->{channel}->{image} || $sub->{icon} });
+ $feed->meta->{livedoor_reader_id} = $sub->{subscribe_id};
+ $feed->meta->{rate} = $sub->{rate};
+ $feed->add_tag($_) for @{$sub->{tags}};
+ $feed->add_tag($sub->{folder}) if $sub->{folder};
+ $feed->updated( Plagger::Date->from_epoch($sub->{modified_on}) ) if $sub->{modified_on};
+ $feed->description($data->{channel}->{description});
+ $feed->meta->{livedoor_reader_subscribers_count} = $data->{channel}->{subscribers_count};
- my $feed = Plagger::Feed->new;
- $feed->type('livedoorReader');
- $feed->title( Plagger::Util::strip_html($data->{channel}->{title}) );
- $feed->link($data->{channel}->{link});
- $feed->url($data->{channel}->{feedlink});
- $feed->image({ url => $data->{channel}->{image} || $sub->{icon} });
- $feed->meta->{livedoor_reader_id} = $sub->{subscribe_id};
- $feed->meta->{rate} = $sub->{rate};
- $feed->add_tag($_) for @{$sub->{tags}};
- $feed->add_tag($sub->{folder}) if $sub->{folder};
- $feed->updated( Plagger::Date->from_epoch($sub->{modified_on}) ) if $sub->{modified_on};
- $feed->description($data->{channel}->{description});
- $feed->meta->{livedoor_reader_subscribers_count} = $data->{channel}->{subscribers_count};
+ for my $item ( @{$data->{items}} ) {
+ my $entry = Plagger::Entry->new;
+ $entry->title($item->{title});
+ $entry->author($item->{author}) if $item->{author};
+ $entry->link($item->{link});
+ # TODO support enclosure
+ $entry->tags([ $item->{category} ]) if $item->{category};
+ $entry->date( Plagger::Date->from_epoch($item->{modified_on}) ); # xxx created_on as well
+ $entry->meta->{livedoor_reader_item_id} = $item->{id};
+ $entry->feed_link($feed->link);
+ $entry->body($item->{body});
- for my $item ( @{$data->{items}} ) {
- my $entry = Plagger::Entry->new;
- $entry->title($item->{title});
- $entry->author($item->{author}) if $item->{author};
- $entry->link($item->{link});
- # TODO support enclosure
- $entry->tags([ $item->{category} ]) if $item->{category};
- $entry->date( Plagger::Date->from_epoch($item->{modified_on}) ); # xxx created_on as well
- $entry->meta->{livedoor_reader_item_id} = $item->{id};
- $entry->feed_link($feed->link);
- $entry->body($item->{body});
-
- $feed->add_entry($entry);
+ $feed->add_entry($entry);
+ }
+ $context->update->add($feed);
+ };
+ if($@){
+ $context->log(error => $@);
+ next;
}
-
- $context->update->add($feed);
+ $self->_request("/api/touch_all", { subscribe_id => $sub->{subscribe_id} })
+ if $mark_read;
}
}