@Override
    public void run() {
      boolean ok = true;
      Feed feed = context.getFeed();
      List<FeedEntry> entries = context.getEntries();
      if (entries.isEmpty() == false) {

        List<String> lastEntries = cache.getLastEntries(feed);
        List<String> currentEntries = Lists.newArrayList();

        List<FeedSubscription> subscriptions = null;
        for (FeedEntry entry : entries) {
          String cacheKey = cache.buildUniqueEntryKey(feed, entry);
          if (!lastEntries.contains(cacheKey)) {
            log.debug("cache miss for {}", entry.getUrl());
            if (subscriptions == null) {
              subscriptions = feedSubscriptionDAO.findByFeed(feed);
            }
            ok &= addEntry(feed, entry, subscriptions);
            metricsBean.entryCacheMiss();
          } else {
            log.debug("cache hit for {}", entry.getUrl());
            metricsBean.entryCacheHit();
          }
          currentEntries.add(cacheKey);
        }
        cache.setLastEntries(feed, currentEntries);
      }

      if (applicationSettingsService.get().isPubsubhubbub()) {
        handlePubSub(feed);
      }
      if (!ok) {
        // requeue asap
        feed.setDisabledUntil(new Date(0));
      }
      metricsBean.feedUpdated();
      taskGiver.giveBack(feed);
    }
  private boolean addEntry(
      final Feed feed, final FeedEntry entry, final List<FeedSubscription> subscriptions) {
    boolean success = false;

    // lock on feed, make sure we are not updating the same feed twice at
    // the same time
    String key1 = StringUtils.trimToEmpty("" + feed.getId());

    // lock on content, make sure we are not updating the same entry
    // twice at the same time
    FeedEntryContent content = entry.getContent();
    String key2 =
        DigestUtils.sha1Hex(StringUtils.trimToEmpty(content.getContent() + content.getTitle()));

    Iterator<Lock> iterator = locks.bulkGet(Arrays.asList(key1, key2)).iterator();
    Lock lock1 = iterator.next();
    Lock lock2 = iterator.next();
    boolean locked1 = false;
    boolean locked2 = false;
    try {
      locked1 = lock1.tryLock(1, TimeUnit.MINUTES);
      locked2 = lock2.tryLock(1, TimeUnit.MINUTES);
      if (locked1 && locked2) {
        feedUpdateService.updateEntry(feed, entry);
        List<User> users = Lists.newArrayList();
        for (FeedSubscription sub : subscriptions) {
          users.add(sub.getUser());
        }
        cache.invalidateUnreadCount(subscriptions.toArray(new FeedSubscription[0]));
        cache.invalidateUserRootCategory(users.toArray(new User[0]));
        metricsBean.entryInserted();
        success = true;
      } else {
        log.error("lock timeout for " + feed.getUrl() + " - " + key1);
      }
    } catch (InterruptedException e) {
      log.error(
          "interrupted while waiting for lock for " + feed.getUrl() + " : " + e.getMessage(), e);
    } finally {
      if (locked1) {
        lock1.unlock();
      }
      if (locked2) {
        lock2.unlock();
      }
    }
    return success;
  }