Auto Download: Exponential backoff when file 404s

This commit is contained in:
Martin Fietz 2016-01-14 19:52:54 +01:00
parent 4f864ab2de
commit f6d5c780e5
4 changed files with 62 additions and 14 deletions

View File

@ -11,6 +11,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import de.danoeh.antennapod.core.asynctask.ImageResource;
import de.danoeh.antennapod.core.storage.DBReader;
@ -75,7 +76,13 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
private List<Chapter> chapters;
private FeedImage image;
private boolean autoDownload = true;
/*
* 0: auto download disabled
* 1: auto download enabled
* > 1: auto download enabled, (approx.) timestamp of the last failed attempt
* where last digit denotes the number of failed attempts
*/
private long autoDownload = 0;
/**
* Any tags assigned to this item
@ -93,7 +100,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
* */
public FeedItem(long id, String title, String link, Date pubDate, String paymentLink, long feedId,
FlattrStatus flattrStatus, boolean hasChapters, FeedImage image, int state,
String itemIdentifier, boolean autoDownload) {
String itemIdentifier, long autoDownload) {
this.id = id;
this.title = title;
this.link = link;
@ -162,7 +169,7 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
FlattrStatus flattrStatus = new FlattrStatus(cursor.getLong(indexFlattrStatus));
int state = cursor.getInt(indexRead);
String itemIdentifier = cursor.getString(indexItemIdentifier);
boolean autoDownload = cursor.getInt(indexAutoDownload) > 0;
long autoDownload = cursor.getLong(indexAutoDownload);
FeedItem item = new FeedItem(id, title, link, pubDate, paymentLink, feedId, flattrStatus,
hasChapters, null, state, itemIdentifier, autoDownload);
@ -449,18 +456,37 @@ public class FeedItem extends FeedComponent implements ShownotesProvider, Flattr
}
public void setAutoDownload(boolean autoDownload) {
this.autoDownload = autoDownload;
this.autoDownload = autoDownload ? 1 : 0;
}
public boolean getAutoDownload() {
return this.autoDownload;
return this.autoDownload > 0;
}
public int getFailedAutoDownloadAttempts() {
if (autoDownload <= 1) {
return 0;
}
int failedAttempts = (int)(autoDownload % 10);
if (failedAttempts == 0) {
failedAttempts = 10;
}
return failedAttempts;
}
public boolean isAutoDownloadable() {
return this.hasMedia() &&
false == this.getMedia().isPlaying() &&
false == this.getMedia().isDownloaded() &&
this.getAutoDownload();
if (media == null || media.isPlaying() || media.isDownloaded() || autoDownload == 0) {
return false;
}
if (autoDownload == 1) {
return true;
}
int failedAttempts = getFailedAutoDownloadAttempts();
double magicValue = 1.767; // 1.767^(10[=#maxNumAttempts]-1) = 168 hours / 7 days
int millisecondsInHour = 3600000;
long waitingTime = (long) (Math.pow(magicValue, failedAttempts - 1) * millisecondsInHour);
long grace = TimeUnit.MINUTES.toMillis(5);
return System.currentTimeMillis() > (autoDownload + waitingTime - grace);
}
/**

View File

@ -206,8 +206,7 @@ public class DownloadService extends Service {
FeedItem item = media.getItem();
if (status.getReason() == DownloadError.ERROR_HTTP_DATA_ERROR &&
Integer.valueOf(status.getReasonDetailed()) == HttpURLConnection.HTTP_NOT_FOUND) {
item.setAutoDownload(false); // for event bus
DBWriter.setFeedItemAutoDownload(item, false);
DBWriter.saveFeedItemAutoDownloadFailed(item).get();
}
// to make lists reload the failed item, we fake an item update
EventBus.getDefault().post(FeedItemEvent.updated(item));

View File

@ -977,11 +977,33 @@ public class DBWriter {
* Sets the 'auto_download'-attribute of specific FeedItem.
*
* @param feedItem FeedItem.
* @param autoDownload true enables auto download, false disables it
*/
public static Future<?> setFeedItemAutoDownload(final FeedItem feedItem,
final boolean autoDownload) {
Log.d(TAG, "FeedItem[id=" + feedItem.getId() + "] SET auto_download " + autoDownload);
return dbExec.submit(() -> {
final PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
adapter.setFeedItemAutoDownload(feedItem, autoDownload ? 1 : 0);
adapter.close();
EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast();
});
}
public static Future<?> saveFeedItemAutoDownloadFailed(final FeedItem feedItem) {
return dbExec.submit(() -> {
int failedAttempts = feedItem.getFailedAutoDownloadAttempts() + 1;
Log.d(TAG, "failedAttempts: " + failedAttempts);
long autoDownload;
if(!feedItem.getAutoDownload() || failedAttempts >= 10) {
autoDownload = 0; // giving up, disable auto download
feedItem.setAutoDownload(false);
} else {
long now = System.currentTimeMillis();
autoDownload = (now / 10) * 10 + failedAttempts;
Log.d(TAG, "now: " + now);
Log.d(TAG, "autoDownload: " + autoDownload);
}
final PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
adapter.setFeedItemAutoDownload(feedItem, autoDownload);
@ -992,7 +1014,8 @@ public class DBWriter {
/**
* Sets the 'auto_download'-attribute of specific FeedItem.
* @param feed This feed's episodes will be processed.
*
* @param feed This feed's episodes will be processed.
* @param autoDownload If true, auto download will be enabled for the feed's episodes. Else,
*/
public static Future<?> setFeedsItemsAutoDownload(final Feed feed,

View File

@ -794,7 +794,7 @@ public class PodDBAdapter {
return status.getId();
}
public void setFeedItemAutoDownload(FeedItem feedItem, boolean autoDownload) {
public void setFeedItemAutoDownload(FeedItem feedItem, long autoDownload) {
ContentValues values = new ContentValues();
values.put(KEY_AUTO_DOWNLOAD, autoDownload);
db.update(TABLE_NAME_FEED_ITEMS, values, KEY_ID + "=?",