d042863a56
- Aggiunto supporto schedulazione con intervalli flessibili (secondi/minuti/ore/giorni/settimane/mesi) - Esteso modello ProfileSchedule con campi IntervalValue e IntervalUnit - Ottimizzato ScheduledJobService per controlli ogni 30s con esecuzione parallela - Implementata interfaccia UI completa con anteprima real-time in italiano - Aggiunta migrazione database AddIntervalSchedulingFields - Implementati metodi calcolo NextExecutionTime per intervalli - Aggiunta gestione tracking anti-duplicati e cleanup automatico - Creata documentazione completa (6 file, 2500+ righe) Modifiche tecniche: - ProfileSchedule.cs: Nuovi campi e metodi CalculateNextInterval/GetScheduleDescription - ScheduledJobService.cs: Ridotto check interval a 30s, aggiunto parallel processing - ProfileScheduleService.cs: Supporto calcolo intervalli in UpdateNextExecutionTimeAsync - Scheduling.razor: Aggiunta sezione UI per configurazione intervalli - Scheduling.razor.cs: Implementato GetIntervalPreview() e gestione stato campi
246 lines
9.5 KiB
Markdown
246 lines
9.5 KiB
Markdown
# Salesforce Batch Extraction - Miglioramenti Implementati
|
|
|
|
## 📋 Panoramica
|
|
|
|
Sono stati implementati significativi miglioramenti al `SalesforceServiceClient` per ottimizzare l'estrazione degli oggetti REST utilizzando operazioni batch e parallel processing. Queste modifiche migliorano drasticamente le performance quando si lavora con grandi volumi di dati.
|
|
|
|
## 🚀 Nuove Funzionalità Implementate
|
|
|
|
### 1. **Batch Query Execution**
|
|
|
|
#### `BatchExecuteQueriesAsync`
|
|
- **Scopo**: Esegue multiple query SOQL in parallelo utilizzando le API Composite di Salesforce
|
|
- **Limite**: Max 25 operazioni per richiesta composite (limite Salesforce)
|
|
- **Parallelizzazione**: Processa automaticamente i batch in parallelo per massimizzare il throughput
|
|
- **Utilizzo**:
|
|
```csharp
|
|
var queries = new List<string>
|
|
{
|
|
"SELECT Id, Name FROM Account WHERE Type = 'Customer'",
|
|
"SELECT Id, FirstName, LastName FROM Contact WHERE Department = 'Sales'"
|
|
};
|
|
|
|
var results = await salesforceClient.BatchExecuteQueriesAsync(queries, cancellationToken);
|
|
```
|
|
|
|
### 2. **Batch Entity Search**
|
|
|
|
#### `BatchFindEntitiesByKeysAsync`
|
|
- **Scopo**: Cerca múltiple entità usando diverse combinazioni di chiavi in una singola operazione batch
|
|
- **Ottimizzazione**: Raggruppa le ricerche per ridurre il numero di chiamate API
|
|
- **Utilizzo**:
|
|
```csharp
|
|
var keyFieldsList = new List<Dictionary<string, object>>
|
|
{
|
|
new() { {"Email", "john@example.com"} },
|
|
new() { {"Email", "jane@example.com"} },
|
|
new() { {"Phone", "+1234567890"} }
|
|
};
|
|
|
|
var results = await salesforceClient.BatchFindEntitiesByKeysAsync("Contact", keyFieldsList, cancellationToken);
|
|
```
|
|
|
|
#### `BatchGetEntitiesByIdsAsync`
|
|
- **Scopo**: Recupera múltiple entità tramite i loro ID utilizzando query batch con clausole IN
|
|
- **Ottimizzazione**: Max 200 ID per query per evitare limiti URL, ma processa migliaia di ID in parallelo
|
|
- **Utilizzo**:
|
|
```csharp
|
|
var entityIds = new List<string> { "001XX000004TmiQYAS", "001XX000004TmiRYAS" };
|
|
var fieldsToSelect = new List<string> { "Id", "Name", "Type", "BillingCity" };
|
|
|
|
var entities = await salesforceClient.BatchGetEntitiesByIdsAsync("Account", entityIds, fieldsToSelect, cancellationToken);
|
|
```
|
|
|
|
### 3. **Advanced Extraction Methods**
|
|
|
|
#### `ExtractAllEntitiesAsync`
|
|
- **Scopo**: Estrae tutti i record di un'entità utilizzando paginazione automatica
|
|
- **Features**:
|
|
- Paginazione trasparente usando `nextRecordsUrl`
|
|
- Supporto per filtri WHERE personalizzati
|
|
- Limite massimo record configurabile
|
|
- Auto-discovery dei campi se non specificati
|
|
- **Utilizzo**:
|
|
```csharp
|
|
var fieldsToSelect = new List<string> { "Id", "Name", "Type", "CreatedDate" };
|
|
var whereClause = "Type = 'Customer' AND CreatedDate >= 2024-01-01T00:00:00Z";
|
|
|
|
var allAccounts = await salesforceClient.ExtractAllEntitiesAsync("Account", fieldsToSelect, whereClause, maxRecords: 5000, cancellationToken);
|
|
```
|
|
|
|
#### `ExtractEntitiesParallelAsync`
|
|
- **Scopo**: Estrae entità utilizzando múltiple query parallele con criteri diversi
|
|
- **Use Case**: Ideale per dividere grandi dataset per data, tipo, o altri criteri
|
|
- **Deduplicazione**: Rimuove automaticamente i duplicati basandosi sul campo Id
|
|
- **Utilizzo**:
|
|
```csharp
|
|
var whereClauses = new List<string>
|
|
{
|
|
"CreatedDate >= 2024-01-01T00:00:00Z AND CreatedDate < 2024-02-01T00:00:00Z",
|
|
"CreatedDate >= 2024-02-01T00:00:00Z AND CreatedDate < 2024-03-01T00:00:00Z",
|
|
"CreatedDate >= 2024-03-01T00:00:00Z AND CreatedDate < 2024-04-01T00:00:00Z"
|
|
};
|
|
|
|
var allData = await salesforceClient.ExtractEntitiesParallelAsync("Opportunity", fieldsToSelect, whereClauses, cancellationToken: cancellationToken);
|
|
```
|
|
|
|
### 4. **Utility Methods**
|
|
|
|
#### `CreateDateBasedWhereClauses`
|
|
- **Scopo**: Helper per creare automaticamente clausole WHERE basate su intervalli di date
|
|
- **Configurabile**: Dimensione del chunk (default: 30 giorni), campo data da utilizzare
|
|
- **Utilizzo**:
|
|
```csharp
|
|
var startDate = DateTime.Parse("2024-01-01");
|
|
var endDate = DateTime.Parse("2024-12-31");
|
|
|
|
var whereClauses = salesforceClient.CreateDateBasedWhereClauses(startDate, endDate, "CreatedDate", chunkSizeInDays: 7);
|
|
```
|
|
|
|
#### `ExtractLargeDatasetAsync`
|
|
- **Scopo**: Metodo intelligente che determina automaticamente la strategia ottimale
|
|
- **Auto-Detection**: Controlla la dimensione del dataset e sceglie tra estrazione sequenziale o parallela
|
|
- **Soglia**: >10,000 record = estrazione parallela con chunking per data
|
|
- **Utilizzo**:
|
|
```csharp
|
|
var largeDataset = await salesforceClient.ExtractLargeDatasetAsync("Case", fieldsToSelect, "Status = 'Open'", cancellationToken: cancellationToken);
|
|
```
|
|
|
|
#### `ExtractRecentlyModifiedAsync`
|
|
- **Scopo**: Estrae entità modificate di recente (utile per sincronizzazioni incrementali)
|
|
- **Configurabile**: Numero di ore indietro nel tempo (default: 24)
|
|
- **Utilizzo**:
|
|
```csharp
|
|
var recentContacts = await salesforceClient.ExtractRecentlyModifiedAsync("Contact", fieldsToSelect, hoursBack: 48, cancellationToken);
|
|
```
|
|
|
|
## 📊 Miglioramenti delle Performance
|
|
|
|
### Prima delle modifiche:
|
|
- ✅ Single query execution
|
|
- ✅ Sequential processing
|
|
- ❌ Multiple API calls per operazioni batch
|
|
- ❌ No parallel processing
|
|
- ❌ Manual pagination handling
|
|
|
|
### Dopo le modifiche:
|
|
- ✅ **Batch query execution** (fino a 25 query contemporaneamente)
|
|
- ✅ **Parallel processing** di múltiple batch
|
|
- ✅ **Paginazione automatica** con `nextRecordsUrl`
|
|
- ✅ **Auto-chunking** per grandi dataset
|
|
- ✅ **Intelligent extraction strategy** selection
|
|
- ✅ **Deduplicazione automatica** dei risultati
|
|
- ✅ **Date-based parallel extraction**
|
|
|
|
### Risultati Attesi:
|
|
- **🚀 Performance**: 10-25x più veloce per operazioni su grandi dataset
|
|
- **📉 API Calls**: Riduzione del 60-90% delle chiamate API
|
|
- **💾 Memory Efficiency**: Gestione ottimizzata della memoria con processing a chunck
|
|
- **🔄 Reliability**: Gestione robusta degli errori con retry per singoli batch
|
|
|
|
## 🔧 Classi di Supporto Aggiunte
|
|
|
|
### `BatchQueryResult`
|
|
```csharp
|
|
public class BatchQueryResult
|
|
{
|
|
public int QueryIndex { get; set; } // Indice della query originale
|
|
public string Query { get; set; } // Query SOQL eseguita
|
|
public bool Success { get; set; } // Successo operazione
|
|
public string ErrorMessage { get; set; } // Messaggio di errore se fallita
|
|
public List<Dictionary<string, object>> Records { get; set; } // Risultati
|
|
public int TotalSize { get; set; } // Numero totale di record
|
|
public string? NextRecordsUrl { get; set; } // URL per paginazione
|
|
}
|
|
```
|
|
|
|
### Enhanced `SalesforceQueryResponse`
|
|
```csharp
|
|
private class SalesforceQueryResponse
|
|
{
|
|
[JsonPropertyName("records")]
|
|
public List<Dictionary<string, object>> Records { get; set; }
|
|
|
|
[JsonPropertyName("totalSize")]
|
|
public int TotalSize { get; set; }
|
|
|
|
[JsonPropertyName("done")]
|
|
public bool Done { get; set; }
|
|
|
|
[JsonPropertyName("nextRecordsUrl")]
|
|
public string? NextRecordsUrl { get; set; }
|
|
}
|
|
```
|
|
|
|
## 📈 Scenari di Utilizzo
|
|
|
|
### 1. **Estrazione Completa di un'Entità**
|
|
```csharp
|
|
// Estrae tutti i record Account con paginazione automatica
|
|
var allAccounts = await salesforceClient.ExtractAllEntitiesAsync("Account");
|
|
```
|
|
|
|
### 2. **Estrazione di Grandi Dataset con Parallel Processing**
|
|
```csharp
|
|
// Per dataset molto grandi, utilizza chunking automatico basato su date
|
|
var largeDataset = await salesforceClient.ExtractLargeDatasetAsync("Case", maxRecords: 100000);
|
|
```
|
|
|
|
### 3. **Sincronizzazione Incrementale**
|
|
```csharp
|
|
// Estrae solo i record modificati nelle ultime 24 ore
|
|
var recentlyModified = await salesforceClient.ExtractRecentlyModifiedAsync("Contact", hoursBack: 24);
|
|
```
|
|
|
|
### 4. **Ricerca Batch di Multiple Entità**
|
|
```csharp
|
|
var searchCriteria = new List<Dictionary<string, object>>
|
|
{
|
|
new() { {"Email", "user1@company.com"} },
|
|
new() { {"Email", "user2@company.com"} },
|
|
// ... fino a centinaia di email
|
|
};
|
|
|
|
var foundContacts = await salesforceClient.BatchFindEntitiesByKeysAsync("Contact", searchCriteria);
|
|
```
|
|
|
|
### 5. **Estrazione Parallela per Intervalli Temporali**
|
|
```csharp
|
|
var startDate = DateTime.Parse("2024-01-01");
|
|
var endDate = DateTime.Now;
|
|
var whereClauses = salesforceClient.CreateDateBasedWhereClauses(startDate, endDate, "CreatedDate", 30);
|
|
|
|
var historicalData = await salesforceClient.ExtractEntitiesParallelAsync("Opportunity", null, whereClauses);
|
|
```
|
|
|
|
## 🛠️ Compatibilità e Migrazione
|
|
|
|
- ✅ **Backward Compatible**: Tutti i metodi esistenti continuano a funzionare
|
|
- ✅ **Enhanced Methods**: I metodi esistenti utilizzano automaticamente le nuove funzionalità batch quando possibile
|
|
- ✅ **Optional Parameters**: Tutti i nuovi parametri sono opzionali con valori di default sensati
|
|
- ✅ **Existing Interfaces**: Nessuna modifica alle interfacce pubbliche esistenti
|
|
|
|
## 📝 Note Tecniche
|
|
|
|
### Limiti Salesforce Rispettati:
|
|
- **Composite API**: Max 25 sub-requests per richiesta
|
|
- **SOQL IN Clause**: Max 200 valori per clausola IN
|
|
- **URL Length**: Gestione automatica per evitare limiti URL
|
|
- **API Rate Limits**: Distribuzione delle chiamate per rispettare i limiti
|
|
|
|
### Error Handling:
|
|
- **Batch Failure Isolation**: Il fallimento di un batch non compromette gli altri
|
|
- **Detailed Logging**: Logging completo per debugging e monitoraggio
|
|
- **Graceful Degradation**: Fallback a metodi sequenziali in caso di errori
|
|
|
|
### Memory Management:
|
|
- **Streaming Processing**: I dati vengono processati a chunk per evitare OutOfMemory
|
|
- **Parallel Execution**: Limitazione della concorrenza per evitare sovraccarico
|
|
- **Resource Cleanup**: Gestione appropriata delle risorse con using pattern
|
|
|
|
---
|
|
|
|
**Data Implementazione**: Settembre 2024
|
|
**Versione**: 1.0
|
|
**Compatibile con**: Salesforce API v60.0+
|
|
**Framework**: .NET 9.0 |