# 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`);
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.graphlit.dev/api-guides/use-cases/feeds/feed-is-done-polling.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
