Skip to content

Commit 9653a2e

Browse files
cursoragentruflin
andcommitted
Fix: Use config value for retryOnConflict in Bulk operations
Co-authored-by: ruflin <ruflin@elastic.co>
1 parent 17b6dcf commit 9653a2e

File tree

3 files changed

+252
-0
lines changed

3 files changed

+252
-0
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--- a/src/Bulk.php
2+
+++ b/src/Bulk.php
3+
@@ -131,6 +131,10 @@ class Bulk
4+
*/
5+
public function addDocument(Document $document, ?string $opType = null): self
6+
{
7+
+ if (!$document->hasRetryOnConflict()) {
8+
+ $retry = $this->_client->getConfigValue('retryOnConflict', 0);
9+
+
10+
+ if ($retry > 0) {
11+
+ $document->setRetryOnConflict($retry);
12+
+ }
13+
+ }
14+
+
15+
$action = AbstractDocumentAction::create($document, $opType);
16+
17+
return $this->addAction($action);
18+
@@ -155,6 +159,10 @@ class Bulk
19+
*/
20+
public function addScript(AbstractScript $script, ?string $opType = null): self
21+
{
22+
+ if (!$script->hasRetryOnConflict()) {
23+
+ $retry = $this->_client->getConfigValue('retryOnConflict', 0);
24+
+
25+
+ if ($retry > 0) {
26+
+ $script->setRetryOnConflict($retry);
27+
+ }
28+
+ }
29+
+
30+
$action = AbstractDocumentAction::create($script, $opType);
31+
32+
return $this->addAction($action);
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Elastica Issue #2219 Investigation Report
2+
3+
## Issue Summary
4+
**Issue**: BC Break from 7.3.1 to 7.3.2 - `Call to a member function hasConnection() on null`
5+
**Repository**: https://github.com/ruflin/Elastica/issues/2219
6+
**Date**: January 27, 2025
7+
8+
## Root Cause Analysis
9+
10+
### The Problem
11+
The error occurs in `src/Bulk.php` at lines 135 and 161 where the code attempts to call `hasConnection()` and `getConnection()` methods on the Client object, but these methods no longer exist in version 7.3.2.
12+
13+
### What Changed Between 7.3.1 and 7.3.2
14+
15+
The critical change was introduced in the `src/Bulk.php` file where the following code was added:
16+
17+
```php
18+
// In addDocument() method (line ~135)
19+
if (!$document->hasRetryOnConflict() && $this->_client->hasConnection() && $this->_client->getConnection()->hasParam('retryOnConflict') && ($retry = $this->_client->getConnection()->getParam('retryOnConflict')) > 0) {
20+
$document->setRetryOnConflict($retry);
21+
}
22+
23+
// In addScript() method (line ~161)
24+
if (!$script->hasRetryOnConflict() && $this->_client->hasConnection() && $this->_client->getConnection()->hasParam('retryOnConflict') && ($retry = $this->_client->getConnection()->getParam('retryOnConflict')) > 0) {
25+
$script->setRetryOnConflict($retry);
26+
}
27+
```
28+
29+
### Why This Breaks
30+
31+
1. **Connection Class Removed**: In Elastica 8.0, the `Elastica\Connection` class and related classes were removed (as documented in CHANGELOG.md lines 114-121).
32+
33+
2. **hasConnection() Method Missing**: The `Client` class no longer has a `hasConnection()` method since the Connection class was removed.
34+
35+
3. **getConnection() Method Missing**: Similarly, `getConnection()` method no longer exists.
36+
37+
4. **Architecture Change**: Elastica 8.0+ uses the official Elasticsearch PHP client's transport layer instead of the custom Connection classes.
38+
39+
## Current State Analysis
40+
41+
### What Works Now
42+
The current codebase (9.x branch) has already been fixed. The problematic code in `src/Bulk.php` now uses:
43+
44+
```php
45+
// Current working implementation
46+
if (!$document->hasRetryOnConflict()) {
47+
$retry = $this->_client->getConfigValue('retryOnConflict', 0);
48+
if ($retry > 0) {
49+
$document->setRetryOnConflict($retry);
50+
}
51+
}
52+
```
53+
54+
### The Fix Applied
55+
The fix replaces the old Connection-based approach with direct configuration access:
56+
- `$this->_client->hasConnection()` → removed
57+
- `$this->_client->getConnection()->hasParam('retryOnConflict')``$this->_client->getConfigValue('retryOnConflict', 0)`
58+
- `$this->_client->getConnection()->getParam('retryOnConflict')``$this->_client->getConfigValue('retryOnConflict', 0)`
59+
60+
## Proposed Solution
61+
62+
### For Version 7.3.2 (Immediate Fix)
63+
The issue can be resolved by applying the same fix that was implemented in later versions:
64+
65+
```php
66+
// Replace the problematic code in src/Bulk.php
67+
// OLD (broken):
68+
if (!$document->hasRetryOnConflict() && $this->_client->hasConnection() && $this->_client->getConnection()->hasParam('retryOnConflict') && ($retry = $this->_client->getConnection()->getParam('retryOnConflict')) > 0) {
69+
$document->setRetryOnConflict($retry);
70+
}
71+
72+
// NEW (working):
73+
if (!$document->hasRetryOnConflict()) {
74+
$retry = $this->_client->getConfigValue('retryOnConflict', 0);
75+
if ($retry > 0) {
76+
$document->setRetryOnConflict($retry);
77+
}
78+
}
79+
```
80+
81+
### For Long-term (Recommended)
82+
Users should upgrade to Elastica 8.0+ where this issue has been resolved and the architecture has been modernized.
83+
84+
## Implementation Steps
85+
86+
1. **Immediate Fix**: Apply the configuration-based approach instead of Connection-based approach
87+
2. **Testing**: Verify that retryOnConflict functionality still works correctly
88+
3. **Documentation**: Update any documentation that references the old Connection API
89+
4. **Migration Guide**: Provide clear migration path for users upgrading from 7.3.1
90+
91+
## Related Pull Requests
92+
- No specific PRs were found for issue #2219
93+
- The fix was implemented as part of the broader 8.0 architecture changes
94+
- Related to PR #2188 which removed Connection classes
95+
96+
## Next Steps
97+
1. Create a patch for version 7.3.2 with the configuration-based fix
98+
2. Test the fix thoroughly
99+
3. Release 7.3.3 with the fix
100+
4. Update documentation and migration guides
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Solution for Elastica Issue #2219
2+
3+
## Problem Summary
4+
**Issue**: BC Break from 7.3.1 to 7.3.2 - `Call to a member function hasConnection() on null`
5+
**Root Cause**: Code in `src/Bulk.php` was trying to use removed Connection API methods
6+
**Impact**: Any bulk operations (populate, etc.) fail with fatal error
7+
8+
## Root Cause Analysis
9+
10+
### What Happened
11+
In version 7.3.2, code was added to `src/Bulk.php` that attempted to use the old Connection API:
12+
13+
```php
14+
// BROKEN CODE (7.3.2)
15+
if (!$document->hasRetryOnConflict() && $this->_client->hasConnection() && $this->_client->getConnection()->hasParam('retryOnConflict') && ($retry = $this->_client->getConnection()->getParam('retryOnConflict')) > 0) {
16+
$document->setRetryOnConflict($retry);
17+
}
18+
```
19+
20+
### Why It Failed
21+
1. **Connection Class Removed**: In Elastica 8.0, the `Elastica\Connection` class was removed
22+
2. **Methods Don't Exist**: `hasConnection()` and `getConnection()` methods no longer exist on Client
23+
3. **Architecture Change**: Elastica 8.0+ uses the official Elasticsearch PHP client's transport layer
24+
25+
## Solution Approaches
26+
27+
### Approach 1: Quick Fix for 7.3.2 (Recommended)
28+
Replace the Connection-based code with configuration-based approach:
29+
30+
```php
31+
// FIXED CODE
32+
if (!$document->hasRetryOnConflict()) {
33+
$retry = $this->_client->getConfigValue('retryOnConflict', 0);
34+
if ($retry > 0) {
35+
$document->setRetryOnConflict($retry);
36+
}
37+
}
38+
```
39+
40+
### Approach 2: Upgrade to 8.0+ (Long-term)
41+
The issue is already fixed in Elastica 8.0+ where the architecture was modernized.
42+
43+
## Implementation
44+
45+
### Step 1: Apply the Fix
46+
Replace the problematic code in `src/Bulk.php` at two locations:
47+
48+
1. **In `addDocument()` method** (around line 135)
49+
2. **In `addScript()` method** (around line 161)
50+
51+
### Step 2: Test the Fix
52+
```php
53+
// Test code to verify the fix works
54+
$client = new \Elastica\Client(['hosts' => ['localhost:9200']]);
55+
$index = $client->getIndex('test');
56+
$document = new \Elastica\Document('1', ['field' => 'value']);
57+
58+
// This should not throw the hasConnection() error
59+
$bulk = new \Elastica\Bulk($client);
60+
$bulk->addDocument($document);
61+
$bulk->send();
62+
```
63+
64+
### Step 3: Verify Configuration
65+
Ensure that `retryOnConflict` is properly configured:
66+
67+
```php
68+
$client = new \Elastica\Client([
69+
'hosts' => ['localhost:9200'],
70+
'retryOnConflict' => 3 // This will now work correctly
71+
]);
72+
```
73+
74+
## Files to Modify
75+
76+
### src/Bulk.php
77+
- **Line ~135**: Replace Connection-based retry logic in `addDocument()`
78+
- **Line ~161**: Replace Connection-based retry logic in `addScript()`
79+
80+
## Testing Strategy
81+
82+
### Unit Tests
83+
1. Test that bulk operations work without Connection API
84+
2. Test that retryOnConflict configuration is respected
85+
3. Test both Document and Script bulk operations
86+
87+
### Integration Tests
88+
1. Test with actual Elasticsearch instance
89+
2. Test bulk operations with retryOnConflict > 0
90+
3. Test bulk operations with retryOnConflict = 0 (default)
91+
92+
## Migration Path
93+
94+
### For Users on 7.3.1
95+
1. **Option A**: Apply the fix patch to 7.3.2
96+
2. **Option B**: Stay on 7.3.1 until ready to upgrade to 8.0+
97+
98+
### For Users on 7.3.2
99+
1. **Immediate**: Apply the fix patch
100+
2. **Long-term**: Plan upgrade to 8.0+ for full architecture benefits
101+
102+
### For New Users
103+
- Use Elastica 8.0+ where this issue doesn't exist
104+
105+
## Related Issues
106+
- **Issue #2219**: The main issue being addressed
107+
- **PR #2188**: Removed Connection classes (8.0)
108+
- **PR #2184**: Ported retryOnConflict from 7.x (8.0)
109+
110+
## Next Steps
111+
1. **Immediate**: Create 7.3.3 release with the fix
112+
2. **Documentation**: Update upgrade guides
113+
3. **Communication**: Notify users about the fix
114+
4. **Long-term**: Encourage migration to 8.0+
115+
116+
## Code Quality
117+
- The fix maintains backward compatibility
118+
- No breaking changes to public API
119+
- Preserves existing functionality
120+
- Uses modern configuration approach

0 commit comments

Comments
 (0)