{
  "attachments": [],
  "comments_archived": true,
  "date": "2003-09-26T02:45:29.000Z",
  "layout": "post",
  "title": "Dynamic feed polling times for news aggregators",
  "wordpress_id": 483,
  "wordpress_slug": "dynamic-feed-scan-times",
  "wordpress_url": "http://www.decafbad.com/blog/?p=483",
  "year": "2003",
  "month": "09",
  "day": "25",
  "isDir": false,
  "slug": "dynamic-feed-scan-times",
  "type": "entry",
  "postName": "2003-09-25-dynamic-feed-scan-times",
  "html": "<p>Today, <a href=\"http://www.decafbad.com/cvs/dbagg/&quot;\">my aggregator</a> got\nthe following SQL worked into its <a href=\"http://www.decafbad.com/cvs/dbagg/lib/dbagg/scan.py?rev=HEAD&amp;content-type=text/vnd.viewcvs-markup\">feed poll scheduling machinery</a>:</p>\n\n<pre>SELECT id as source,\n       'update_period' as name,\n       max(1, 1/max((1.0/24.0),\n                    sum(update_count)/(7*24))) AS value \nFROM sources \nLEFT JOIN (\n    SELECT source AS count_id,\n                round(iso8601_to_epoch(created)/(60*60)) AS hour, \n                count(id) AS update_count \n    FROM items \n    WHERE created&gt;epoch_to_iso8601(now()-(7*(24*60*60))) \n    GROUP BY hour\n) ON id=count_id\nGROUP BY source\nORDER BY value</pre>\n\n<p>\nIt's likely that this is really nasty, but I have only a street-level\nworking knowledge of SQL.  Also, a few of the date functions are\nspecific to how I've <a href=\"http://pysqlite.sourceforge.net/documentation/pysqlite/node10.html#SECTION004231000000000000000\">extended sqlite in Python</a>.  It works though, and\nwhat it does is this:\n</p>\n\n<p>\nFor each feed to which I'm subscribed, work out\nan average time between updates for the past week, with a maximum\nperiod of 24 hours and a minimum of 1 hour.\n</p>\n\n<p>\nMy aggregator does this daily, and uses the results to determine how\nfrequently to schedule scans.  In this way, it automatically backs off\non checking feeds which update infrequently, and ramps up its polling\nof more active feeds.  This shortens my feed downloading and scanning\ntime, and is kinder in general to everyone on my subscription list.\n</p>\n\n<p>\nNext, among other things, I have to look into making sure that the\nHTTP client parts of this beast pass all the\n<a href=\"http://diveintomark.org/tests/client/http/\">aggregator client\nHTTP tests</a> that <a href=\"http://diveintomark.org/\">Mark\nPilgrim</a> put together.\n</p>\n\n<p>\n<b>Update</b>: Well, it seemed like a good idea, anyway.  But, on\nfurther examination, it has flaws.  The most notable is that it\nassumes a polling frequency of once per hour.  This works right up\nuntil I start changing the polling frequency with the results of the\ncalculation.  I haven't poked at it yet, but maybe if I take this\ninto account, it'll be more accurate.\n</p>\n\n<p>\nOn the other hand, I've also been thinking about a much simpler\napproach to ramping polling frequency up and down:  Start out at\na poll every hour.  If, after a poll, no new items are found,\ndouble the time until the next poll.  If new items were found,\nhalve the time until the next poll.</p>\n\n<p>\nProvide lower and upper limits to this, say between 1 hour and 1\nweek.  Also, consider the ramp up and ramp down factor as a variable\nsetting too.  Instead of a factor of 2, maybe try 1.5 or even 1.25 for\na more gradual change.  To go even further, I wonder if it would be\nvaluable to dynamically alter this factor itself, to try to get the\npolling time zeroed in on a realistic polling time.\n</p>\n\n<p>\nOkay.  There the simpler approach leaves simplicity.  I'm sure there's\nsome decently elegant math that could be pulled in here.  :)\n</p>\n\n\n<!--more-->\n\n\n<p>shortname=dynamic_feed_scan_times</p>\n<div id=\"comments\" class=\"comments archived-comments\"><h3>Archived Comments</h3>\n<ul class=\"comments\">\n<li class=\"comment\" id=\"comment-221087768\">\n<div class=\"meta\">\n<div class=\"author\">\n<a class=\"avatar image\" rel=\"nofollow\" href=\"http://24.102.209.201/weblogs/ben/\"><img src=\"http://www.gravatar.com/avatar.php?gravatar_id=588bdfdda82be46c638d6956c55ebc38&amp;size=32&amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png\" width=\"\" height=\"\"></a>\n<a class=\"avatar name\" rel=\"nofollow\" href=\"http://24.102.209.201/weblogs/ben/\">Gnomon</a>\n</div>\n\n\n<p><a href=\"#comment-221087768\" class=\"permalink\"><time datetime=\"2003-09-26T09:56:09\">2003-09-26T09:56:09</time></a></p>\n</div>\n\n\n<div class=\"content\">Why not just go the TCP/IP route - Additive Increase / Multiplicative Decrease? Start by setting the check-interval to one hour (or whatever). For each feed, if a new post is found, cut the check-interval for that feed by half; if no new post is found, increase the check-interval by an hour.\nIt's not optimal, and it won't automagically zero in on the predicted post times of individual feeds, but it strikes a nice balance between bandwidth politeness, update rapidity and conceptual simplicity. The constant values (initial check-interval, check-interval increment, check-interval multiplier) can be tweaked for different behavioural styles.</div>\n\n\n</li>\n<li class=\"comment\" id=\"comment-221087769\">\n<div class=\"meta\">\n<div class=\"author\">\n<a class=\"avatar image\" rel=\"nofollow\" href=\"http://www.decafbad.com/blog\"><img src=\"http://www.gravatar.com/avatar.php?gravatar_id=2ac2cffd36ada8c734b90e02a1e5c1ac&amp;size=32&amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png\" width=\"\" height=\"\"></a>\n<a class=\"avatar name\" rel=\"nofollow\" href=\"http://www.decafbad.com/blog\">l.m.orchard</a>\n</div>\n\n\n<p><a href=\"#comment-221087769\" class=\"permalink\"><time datetime=\"2003-09-26T11:04:24\">2003-09-26T11:04:24</time></a></p>\n</div>\n\n\n<div class=\"content\">Hmm...  I knew that this was something that someone had already handled somewhere.  :)  I'm just not all that familiar with the details of TCP/IP, but this sounds pretty much like a workable approach I'd like to go with.</div>\n\n\n</li>\n<li class=\"comment\" id=\"comment-221087770\">\n<div class=\"meta\">\n<div class=\"author\">\n<a class=\"avatar image\" rel=\"nofollow\" href=\"http://www.decafbad.com/blog\"><img src=\"http://www.gravatar.com/avatar.php?gravatar_id=2ac2cffd36ada8c734b90e02a1e5c1ac&amp;size=32&amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png\" width=\"\" height=\"\"></a>\n<a class=\"avatar name\" rel=\"nofollow\" href=\"http://www.decafbad.com/blog\">l.m.orchard</a>\n</div>\n\n\n<p><a href=\"#comment-221087770\" class=\"permalink\"><time datetime=\"2003-09-26T11:07:00\">2003-09-26T11:07:00</time></a></p>\n</div>\n\n\n<div class=\"content\">Oh!  For a second I thought that what you're suggesting was basically what I was already working on with my multiplying/dividing by a factor...  But you're talking about something that ADDS to increase and MULTIPLIES to decrease, which is something much more biased to back off than ramp up, which seems very polite to me.  Yay!</div>\n\n\n</li>\n</ul>\n\n\n</div>\n\n\n",
  "body": "<p>Today, <a href=http://www.decafbad.com/cvs/dbagg/\">my aggregator</a> got\r\nthe following SQL worked into its <a href=\"http://www.decafbad.com/cvs/dbagg/lib/dbagg/scan.py?rev=HEAD&content-type=text/vnd.viewcvs-markup\">feed poll scheduling machinery</a>:</p>\r\n\r\n<pre>SELECT id as source,\r\n       'update_period' as name,\r\n       max(1, 1/max((1.0/24.0),\r\n                    sum(update_count)/(7*24))) AS value \r\nFROM sources \r\nLEFT JOIN (\r\n    SELECT source AS count_id,\r\n                round(iso8601_to_epoch(created)/(60*60)) AS hour, \r\n                count(id) AS update_count \r\n    FROM items \r\n    WHERE created>epoch_to_iso8601(now()-(7*(24*60*60))) \r\n    GROUP BY hour\r\n) ON id=count_id\r\nGROUP BY source\r\nORDER BY value</pre>\r\n\r\n<p>\r\nIt's likely that this is really nasty, but I have only a street-level\r\nworking knowledge of SQL.  Also, a few of the date functions are\r\nspecific to how I've <a href=\"http://pysqlite.sourceforge.net/documentation/pysqlite/node10.html#SECTION004231000000000000000\">extended sqlite in Python</a>.  It works though, and\r\nwhat it does is this:\r\n</p>\r\n\r\n<p>\r\nFor each feed to which I'm subscribed, work out\r\nan average time between updates for the past week, with a maximum\r\nperiod of 24 hours and a minimum of 1 hour.\r\n</p>\r\n\r\n<p>\r\nMy aggregator does this daily, and uses the results to determine how\r\nfrequently to schedule scans.  In this way, it automatically backs off\r\non checking feeds which update infrequently, and ramps up its polling\r\nof more active feeds.  This shortens my feed downloading and scanning\r\ntime, and is kinder in general to everyone on my subscription list.\r\n</p>\r\n\r\n<p>\r\nNext, among other things, I have to look into making sure that the\r\nHTTP client parts of this beast pass all the\r\n<a href=\"http://diveintomark.org/tests/client/http/\">aggregator client\r\nHTTP tests</a> that <a href=\"http://diveintomark.org/\">Mark\r\nPilgrim</a> put together.\r\n</p>\r\n\r\n<p>\r\n<b>Update</b>: Well, it seemed like a good idea, anyway.  But, on\r\nfurther examination, it has flaws.  The most notable is that it\r\nassumes a polling frequency of once per hour.  This works right up\r\nuntil I start changing the polling frequency with the results of the\r\ncalculation.  I haven't poked at it yet, but maybe if I take this\r\ninto account, it'll be more accurate.\r\n</p>\r\n\r\n<p>\r\nOn the other hand, I've also been thinking about a much simpler\r\napproach to ramping polling frequency up and down:  Start out at\r\na poll every hour.  If, after a poll, no new items are found,\r\ndouble the time until the next poll.  If new items were found,\r\nhalve the time until the next poll.</p>\r\n\r\n<p>\r\nProvide lower and upper limits to this, say between 1 hour and 1\r\nweek.  Also, consider the ramp up and ramp down factor as a variable\r\nsetting too.  Instead of a factor of 2, maybe try 1.5 or even 1.25 for\r\na more gradual change.  To go even further, I wonder if it would be\r\nvaluable to dynamically alter this factor itself, to try to get the\r\npolling time zeroed in on a realistic polling time.\r\n</p>\r\n\r\n<p>\r\nOkay.  There the simpler approach leaves simplicity.  I'm sure there's\r\nsome decently elegant math that could be pulled in here.  :)\r\n</p>\r\n<!--more-->\r\nshortname=dynamic_feed_scan_times\r\n\r\n<div id=\"comments\" class=\"comments archived-comments\">\r\n            <h3>Archived Comments</h3>\r\n            \r\n        <ul class=\"comments\">\r\n            \r\n        <li class=\"comment\" id=\"comment-221087768\">\r\n            <div class=\"meta\">\r\n                <div class=\"author\">\r\n                    <a class=\"avatar image\" rel=\"nofollow\" \r\n                       href=\"http://24.102.209.201/weblogs/ben/\"><img src=\"http://www.gravatar.com/avatar.php?gravatar_id=588bdfdda82be46c638d6956c55ebc38&amp;size=32&amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png\"/></a>\r\n                    <a class=\"avatar name\" rel=\"nofollow\" \r\n                       href=\"http://24.102.209.201/weblogs/ben/\">Gnomon</a>\r\n                </div>\r\n                <a href=\"#comment-221087768\" class=\"permalink\"><time datetime=\"2003-09-26T09:56:09\">2003-09-26T09:56:09</time></a>\r\n            </div>\r\n            <div class=\"content\">Why not just go the TCP/IP route - Additive Increase / Multiplicative Decrease? Start by setting the check-interval to one hour (or whatever). For each feed, if a new post is found, cut the check-interval for that feed by half; if no new post is found, increase the check-interval by an hour.\r\n\r\nIt's not optimal, and it won't automagically zero in on the predicted post times of individual feeds, but it strikes a nice balance between bandwidth politeness, update rapidity and conceptual simplicity. The constant values (initial check-interval, check-interval increment, check-interval multiplier) can be tweaked for different behavioural styles.</div>\r\n            \r\n        </li>\r\n    \r\n        <li class=\"comment\" id=\"comment-221087769\">\r\n            <div class=\"meta\">\r\n                <div class=\"author\">\r\n                    <a class=\"avatar image\" rel=\"nofollow\" \r\n                       href=\"http://www.decafbad.com/blog\"><img src=\"http://www.gravatar.com/avatar.php?gravatar_id=2ac2cffd36ada8c734b90e02a1e5c1ac&amp;size=32&amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png\"/></a>\r\n                    <a class=\"avatar name\" rel=\"nofollow\" \r\n                       href=\"http://www.decafbad.com/blog\">l.m.orchard</a>\r\n                </div>\r\n                <a href=\"#comment-221087769\" class=\"permalink\"><time datetime=\"2003-09-26T11:04:24\">2003-09-26T11:04:24</time></a>\r\n            </div>\r\n            <div class=\"content\">Hmm...  I knew that this was something that someone had already handled somewhere.  :)  I'm just not all that familiar with the details of TCP/IP, but this sounds pretty much like a workable approach I'd like to go with.</div>\r\n            \r\n        </li>\r\n    \r\n        <li class=\"comment\" id=\"comment-221087770\">\r\n            <div class=\"meta\">\r\n                <div class=\"author\">\r\n                    <a class=\"avatar image\" rel=\"nofollow\" \r\n                       href=\"http://www.decafbad.com/blog\"><img src=\"http://www.gravatar.com/avatar.php?gravatar_id=2ac2cffd36ada8c734b90e02a1e5c1ac&amp;size=32&amp;default=http://mediacdn.disqus.com/1320279820/images/noavatar32.png\"/></a>\r\n                    <a class=\"avatar name\" rel=\"nofollow\" \r\n                       href=\"http://www.decafbad.com/blog\">l.m.orchard</a>\r\n                </div>\r\n                <a href=\"#comment-221087770\" class=\"permalink\"><time datetime=\"2003-09-26T11:07:00\">2003-09-26T11:07:00</time></a>\r\n            </div>\r\n            <div class=\"content\">Oh!  For a second I thought that what you're suggesting was basically what I was already working on with my multiplying/dividing by a factor...  But you're talking about something that ADDS to increase and MULTIPLIES to decrease, which is something much more biased to back off than ramp up, which seems very polite to me.  Yay!</div>\r\n            \r\n        </li>\r\n    \r\n        </ul>\r\n    \r\n        </div>\r\n    ",
  "parentPath": "./content/posts/archives/2003",
  "path": "2003/09/25/dynamic-feed-scan-times",
  "summary": "Today, my aggregator got\nthe following SQL worked into its feed poll scheduling machinery:\n\nSELECT id as source,\n       'update_period' as name,\n       max(1, 1/max((1.0/24.0),\n                    sum(update_count)/(7*24))) AS value \nFROM sources \nLEFT JOIN (\n    SELECT source AS count_id,\n                round(iso8601_to_epoch(created)/(60*60)) AS hour, \n                count(id) AS update_count \n    FROM items \n    WHERE created>epoch_to_iso8601(now()-(7*(24*60*60))) \n    GROUP BY hour\n) ON id=count_id\nGROUP BY source\nORDER BY value\n\n\nIt's likely that this is really nasty, but I have only a street-level\nworking knowledge of SQL.  Also, a few of the date functions are\nspecific to how I've extended sqlite in Python.  It works though, and\nwhat it does is this:\n\n\n\nFor each feed to which I'm subscribed, work out\nan average time between updates for the past week, with a maximum\nperiod of 24 hours and a minimum of 1 hour.\n\n\n\nMy aggregator does this daily, and uses the results to determine how\nfrequently to schedule scans.  In this way, it automatically backs off\non checking feeds which update infrequently, and ramps up its polling\nof more active feeds.  This shortens my feed downloading and scanning\ntime, and is kinder in general to everyone on my subscription list.\n\n\n\nNext, among other things, I have to look into making sure that the\nHTTP client parts of this beast pass all the\naggregator client\nHTTP tests that Mark\nPilgrim put together.\n\n\n\nUpdate: Well, it seemed like a good idea, anyway.  But, on\nfurther examination, it has flaws.  The most notable is that it\nassumes a polling frequency of once per hour.  This works right up\nuntil I start changing the polling frequency with the results of the\ncalculation.  I haven't poked at it yet, but maybe if I take this\ninto account, it'll be more accurate.\n\n\n\nOn the other hand, I've also been thinking about a much simpler\napproach to ramping polling frequency up and down:  Start out at\na poll every hour.  If, after a poll, no new items are found,\ndouble the time until the next poll.  If new items were found,\nhalve the time until the next poll.\n\n\nProvide lower and upper limits to this, say between 1 hour and 1\nweek.  Also, consider the ramp up and ramp down factor as a variable\nsetting too.  Instead of a factor of 2, maybe try 1.5 or even 1.25 for\na more gradual change.  To go even further, I wonder if it would be\nvaluable to dynamically alter this factor itself, to try to get the\npolling time zeroed in on a realistic polling time.\n\n\n\nOkay.  There the simpler approach leaves simplicity.  I'm sure there's\nsome decently elegant math that could be pulled in here.  :)",
  "needsBuild": true,
  "prevPostPath": "2003/09/25/atom-is-its-name-o",
  "prevPostTitle": "Atom is its Name-O?",
  "nextPostPath": "2003/09/29/dynamic-polling-freq-too",
  "nextPostTitle": "Dynamic polling times for news aggregators, II"
}