> For the complete documentation index, see [llms.txt](https://docs.graphlit.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.graphlit.dev/api-guides/use-cases/feeds/feed-is-done-polling.md).

# Poll for Completion

## User Intent

"I want to know when a feed has finished its initial sync"

## Operation

* **SDK Method**: `graphlit.isFeedDone()`
* **GraphQL**: `isFeedDone` query
* **Entity Type**: Feed
* **Common Use Cases**: Wait for initial feed sync, verify feed completion before querying content

## TypeScript (Canonical)

```typescript
import { Graphlit } from 'graphlit-client';

const graphlit = new Graphlit();

// After creating a feed
const feedResponse = await graphlit.createFeed(feedInput);
const feedId = feedResponse.createFeed.id;

console.log(`Feed created: ${feedId}`);

// Poll for completion
const maxAttempts = 60; // 10 minutes max (60 * 10 seconds)

for (let attempts = 1; attempts <= maxAttempts; attempts++) {
  const status = await graphlit.isFeedDone(feedId);
  if (status.isFeedDone.result) {
    console.log('Feed sync complete!');

    const contents = await graphlit.queryContents({
      feeds: [{ id: feedId }],
    });

    console.log(`Synced ${contents.contents.results.length} items`);
    return;
  }

  console.log(`Still syncing... (${attempts}/${maxAttempts})`);
  await new Promise((resolve) => setTimeout(resolve, 10_000));
}

console.log('Feed sync timeout - still processing');
```

**Python**:

```python
feed_response = await graphlit.create_feed(feed_input)
feed_id = feed_response.createFeed.id

is_done = False
attempts = 0
max_attempts = 60

while not is_done and attempts < max_attempts:
    status = await graphlit.isFeedDone(feed_id)
    is_done = status.isFeedDone.result if status.isFeedDone else False

    if not is_done:
        attempts += 1
        print(f"Still syncing... ({attempts}/{max_attempts})")
        await asyncio.sleep(10)

if is_done:
    print("Feed sync complete!")
```

**C#**:

```csharp
using Graphlit;
using System.Threading.Tasks;

var graphlit = new Graphlit();

var feedResponse = await graphlit.CreateFeed(feedInput);
var feedId = feedResponse.CreateFeed.Id;

// Poll for completion (PascalCase)
bool isDone = false;
int attempts = 0;
int maxAttempts = 60;

while (!isDone && attempts < maxAttempts)
{
    var status = await graphlit.IsFeedDone(feedId);
    isDone = status.IsFeedDone?.Result ?? false;
    
    if (!isDone)
    {
        attempts++;
        Console.WriteLine($"Still syncing... ({attempts}/{maxAttempts})");
        await Task.Delay(10000); // Wait 10 seconds
    }
}

if (isDone)
{
    Console.WriteLine("Feed sync complete!");
}
```

## Parameters

### Required

* **`id`** (string): Feed ID to check

## Response

```typescript
{
  isFeedDone: {
    result: boolean;  // true = sync complete, false = still syncing
  }
}
```

## Developer Hints

### Only for Initial Sync

`isFeedDone()` indicates **initial sync completion**, not ongoing monitoring:

```typescript
// After feed creation
const feed = await graphlit.createFeed(feedInput);

// isFeedDone checks initial sync
await waitUntilFeedDone(feed.createFeed.id);

// After initial sync, feed continues to monitor for new content
// You don't need to call isFeedDone again
```

**Important**: Once initial sync completes, the feed continuously monitors for new content automatically.

### Recommended Polling Interval

```typescript
// Too frequent (wasteful)
await new Promise(resolve => setTimeout(resolve, 1000)); //  Every 1 second

// Good balance
await new Promise(resolve => setTimeout(resolve, 10000)); //  Every 10 seconds

// For very large feeds
await new Promise(resolve => setTimeout(resolve, 30000)); //  Every 30 seconds
```

**Why 10 seconds?**: Balance between responsiveness and API efficiency. Initial feed syncs typically take 1-10 minutes depending on content volume.

### 🕐 Timeout Considerations

```typescript
// Typical sync times by feed type
const timeouts = {
  rss: 2 minutes,          // Small: 10-100 items
  slack: 5 minutes,        // Medium: 100s-1000s of messages
  googleDrive: 10 minutes, // Large: Many files
  web: 15 minutes          // Very large: Deep crawls
};

// Adjust maxAttempts based on feed type
const maxAttempts = feedType === 'rss' ? 12 : 60; // 2 min vs 10 min
```

### Helper Function Pattern

```typescript
async function waitForFeedCompletion(
  feedId: string,
  timeoutMinutes: number = 10,
  pollIntervalSeconds: number = 10
): Promise<boolean> {
  const maxAttempts = (timeoutMinutes * 60) / pollIntervalSeconds;
  let attempts = 0;
  
  while (attempts < maxAttempts) {
    const status = await graphlit.isFeedDone(feedId);
    
    if (status.isFeedDone.result) {
      return true; // Success
    }
    
    attempts++;
    await new Promise(resolve => setTimeout(resolve, pollIntervalSeconds * 1000));
  }
  
  return false; // Timeout
}

// Usage
const completed = await waitForFeedCompletion(feedId, 10, 10);
if (completed) {
  console.log('Ready to query content');
} else {
  console.log('Timeout - feed still processing');
}
```

## Variations

### 1. Basic Polling with Progress

Simple polling with progress updates:

```typescript
async function pollFeedWithProgress(feedId: string) {
  console.log('Waiting for feed sync to complete...');
  
  let isDone = false;
  let attempts = 0;
  
  while (!isDone && attempts < 60) {
    const status = await graphlit.isFeedDone(feedId);
    isDone = status.isFeedDone.result || false;
    
    if (!isDone) {
      attempts++;
      const elapsed = attempts * 10; // seconds
      console.log(`⏳ ${elapsed}s elapsed...`);
      await new Promise(resolve => setTimeout(resolve, 10000));
    }
  }
  
  console.log(isDone ? ' Complete!' : '⏰ Timeout');
  return isDone;
}
```

### 2. Polling with Content Count Tracking

Track synced content during polling:

```typescript
async function pollWithContentTracking(feedId: string) {
  let isDone = false;
  let previousCount = 0;
  
  while (!isDone) {
    const status = await graphlit.isFeedDone(feedId);
    isDone = status.isFeedDone.result || false;
    
    // Check how many items synced so far
    const contents = await graphlit.queryContents({
      feeds: [{ id: feedId }],
      limit: 1  // Just get count, not all items
    });
    
    const currentCount = contents.contents.results.length;
    
    if (currentCount > previousCount) {
      console.log(`📥 Synced ${currentCount} items so far...`);
      previousCount = currentCount;
    }
    
    if (!isDone) {
      await new Promise(resolve => setTimeout(resolve, 10000));
    }
  }
  
  console.log(` Sync complete! Total: ${previousCount} items`);
}
```

### 3. Parallel Feed Polling

Poll multiple feeds simultaneously:

```typescript
async function pollMultipleFeeds(feedIds: string[]) {
  const pollPromises = feedIds.map(async (feedId) => {
    let isDone = false;
    
    while (!isDone) {
      const status = await graphlit.isFeedDone(feedId);
      isDone = status.isFeedDone.result || false;
      
      if (!isDone) {
        await new Promise(resolve => setTimeout(resolve, 10000));
      }
    }
    
    return feedId;
  });
  
  // Wait for all feeds to complete
  const completedFeeds = await Promise.all(pollPromises);
  console.log(`All ${completedFeeds.length} feeds synced!`);
  
  return completedFeeds;
}

// Usage
const feedIds = [feed1Id, feed2Id, feed3Id];
await pollMultipleFeeds(feedIds);
```

### 4. Exponential Backoff Polling

Reduce API calls with backoff:

```typescript
async function pollWithBackoff(feedId: string) {
  let isDone = false;
  let interval = 5000; // Start at 5 seconds
  const maxInterval = 60000; // Max 60 seconds
  
  while (!isDone) {
    const status = await graphlit.isFeedDone(feedId);
    isDone = status.isFeedDone.result || false;
    
    if (!isDone) {
      console.log(`Waiting ${interval / 1000}s before next check...`);
      await new Promise(resolve => setTimeout(resolve, interval));
      
      // Exponential backoff
      interval = Math.min(interval * 1.5, maxInterval);
    }
  }
  
  console.log('Feed sync complete!');
}
```

### 5. Polling with Timeout Promise

Use Promise.race for cleaner timeout:

```typescript
async function pollWithTimeout(
  feedId: string,
  timeoutMs: number = 600000 // 10 minutes
): Promise<boolean> {
  const pollPromise = (async () => {
    let isDone = false;
    
    while (!isDone) {
      const status = await graphlit.isFeedDone(feedId);
      isDone = status.isFeedDone.result || false;
      
      if (!isDone) {
        await new Promise(resolve => setTimeout(resolve, 10000));
      }
    }
    
    return true;
  })();
  
  const timeoutPromise = new Promise<boolean>((resolve) => {
    setTimeout(() => resolve(false), timeoutMs);
  });
  
  const completed = await Promise.race([pollPromise, timeoutPromise]);
  
  if (!completed) {
    console.log('⏰ Feed sync timeout');
  }
  
  return completed;
}
```

### 6. Query Content After Completion

Complete workflow from feed creation to content query:

```typescript
// Create feed
const feedResponse = await graphlit.createFeed({
  name: 'News RSS',
  type: FeedTypes.Rss,
  rss: {
    uri: 'https://news.example.com/rss'
  }
});

const feedId = feedResponse.createFeed.id;

// Wait for sync
const completed = await waitForFeedCompletion(feedId);

if (completed) {
  // Query synced content
  const contents = await graphlit.queryContents({
    feeds: [{ id: feedId }],
    orderBy: OrderByTypes.CreationDate,
    direction: OrderDirectionTypes.Descending,
    limit: 10
  });
  
  console.log('Latest synced items:');
  contents.contents.results.forEach((item, index) => {
    console.log(`${index + 1}. ${item.name}`);
  });
}
```

## Common Issues

**Issue**: `isFeedDone()` always returns false\
**Solution**: Feed may be stuck. Check feed state with `getFeed()`. Look for error state.

**Issue**: Polling times out but feed has content\
**Solution**: Feed may be partially synced but not "done". Increase timeout or query content anyway.

**Issue**: `Feed not found` error\
**Solution**: Verify feed ID is correct. Check that feed wasn't deleted.

**Issue**: Feed completes immediately (no content synced)\
**Solution**: Check feed configuration. May have OAuth token issues or incorrect settings.

**Issue**: Memory leak from long polling\
**Solution**: Ensure you have proper timeout/max attempts. Don't poll indefinitely.

## Production Example

**Poll helper function**:

```typescript
async function waitForFeed(feedId: string, maxMinutes: number = 10): Promise<boolean> {
  const maxAttempts = maxMinutes * 6; // 6 checks per minute (10s intervals)
  let attempts = 0;
  
  while (attempts < maxAttempts) {
    const status = await graphlit.isFeedDone(feedId);
    
    if (status.isFeedDone.result) {
      return true;
    }
    
    attempts++;
    await new Promise(resolve => setTimeout(resolve, 10000));
  }
  
  return false;
}

// Usage
const feedId = response.createFeed.id;
const success = await waitForFeed(feedId, 10);

if (success) {
  const contents = await graphlit.queryContents({ feeds: [{ id: feedId }] });
  console.log(`Synced ${contents.contents.results.length} items`);
}
```
