Your billing query approach needs a complete redesign to handle this data volume efficiently. Let me address all three optimization areas:
OData Query Optimization:
Replace your single large query with an aggregation-based approach using $apply:
GET /DeviceUsage?$filter=deviceId eq 'METER_123' and timestamp ge 2025-01-01 and timestamp le 2025-01-31
&$apply=groupby((deviceId),aggregate(usageValue with sum as totalUsage))
This returns a single aggregated row instead of 50K records. For daily breakdowns, add date grouping:
&$apply=groupby((deviceId,date(timestamp)),aggregate(usageValue with sum as dailyUsage))
This returns 31 rows (one per day) instead of 50K, reducing response time from 60+ seconds to under 2 seconds.
Timeout Configuration:
While you can increase timeouts, the proper solution is fixing the query. However, for legitimate cases requiring longer execution:
- Update the destination configuration (if using SAP BTP):
{
"timeout": 180000,
"readTimeout": 180000
}
- For direct service calls, set HTTP client timeout in your application:
HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(30))
.build();
- IoT Time Series service has a hard limit of 300 seconds that cannot be exceeded. Beyond this, you must use pagination.
Pagination Implementation:
For scenarios requiring raw data (not aggregates), implement proper pagination with server-side cursor:
// Initial request
GET /DeviceUsage?$filter=... &$top=1000 &$orderby=timestamp
// Subsequent requests use skiptoken from @odata.nextLink
GET /DeviceUsage?$filter=... &$skiptoken={token}
Implement this in your billing service:
List<Usage> allRecords = new ArrayList<>();
String nextUrl = initialQuery;
while (nextUrl != null) {
Response resp = httpClient.get(nextUrl);
allRecords.addAll(resp.getValue());
nextUrl = resp.getNextLink();
}
Recommended Billing Architecture:
For monthly billing, pre-aggregate data using scheduled background jobs:
- Create a daily aggregation job that runs at midnight
- Store daily summaries in a separate billing table
- Monthly billing queries only aggregate 31 daily records instead of 50K raw records
- Use IoT Business Rules to trigger aggregation on data arrival
This approach reduces monthly billing report generation from minutes to seconds. The aggregation overhead is distributed throughout the month rather than concentrated at billing time.
Implement the $apply aggregation first - it will immediately solve your timeout issue for standard billing use cases.