• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

uber / cadence-java-client / 2409

03 Jul 2024 08:33PM CUT coverage: 61.467% (-0.05%) from 61.518%
2409

push

buildkite

web-flow
Avoid consuming ByteBuffers (#913)

A ByteBuffer is a pointer to a byte[] with a starting position, a current position, and a limit. Any function that reads from its contents updates the current position. Both TracingPropagator and WorkflowUtils copy the entirety of its contents, and in doing so they mutate the current position. WorkflowUtils resets it afterwards but this still isn't thread-safe as another thread may be trying to read it.

By duplicating the ByteBuffer (copying only the metadata, not the actual contents) we avoid modifying it. It doesn't seem likely that there's real impact in either of these cases beyond unit tests, where these ByteBuffers stick around in the workflow history and are repeatedly serialized/deserialized. Modifying them during serialization can create test flakiness as that can trigger exceptions.

2 of 2 new or added lines in 2 files covered. (100.0%)

10 existing lines in 4 files now uncovered.

11972 of 19477 relevant lines covered (61.47%)

0.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.18
/src/main/java/com/uber/cadence/internal/replay/DecisionStateMachineBase.java
1
/*
2
 *  Copyright 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
 *
4
 *  Modifications copyright (C) 2017 Uber Technologies, Inc.
5
 *
6
 *  Licensed under the Apache License, Version 2.0 (the "License"). You may not
7
 *  use this file except in compliance with the License. A copy of the License is
8
 *  located at
9
 *
10
 *  http://aws.amazon.com/apache2.0
11
 *
12
 *  or in the "license" file accompanying this file. This file is distributed on
13
 *  an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
14
 *  express or implied. See the License for the specific language governing
15
 *  permissions and limitations under the License.
16
 */
17

18
package com.uber.cadence.internal.replay;
19

20
import com.uber.cadence.HistoryEvent;
21
import java.util.ArrayList;
22
import java.util.List;
23

24
abstract class DecisionStateMachineBase implements DecisionStateMachine {
25

26
  protected DecisionState state = DecisionState.CREATED;
1✔
27

28
  protected List<String> stateHistory = new ArrayList<String>();
1✔
29

30
  private final DecisionId id;
31

32
  public DecisionStateMachineBase(DecisionId id) {
1✔
33
    this.id = id;
1✔
34
    stateHistory.add(state.toString());
1✔
35
  }
1✔
36

37
  /** Used for unit testing. */
38
  protected DecisionStateMachineBase(DecisionId id, DecisionState state) {
×
39
    this.id = id;
×
40
    this.state = state;
×
41
    stateHistory.add(state.toString());
×
42
  }
×
43

44
  @Override
45
  public DecisionState getState() {
46
    return state;
×
47
  }
48

49
  @Override
50
  public DecisionId getId() {
51
    return id;
×
52
  }
53

54
  @Override
55
  public boolean isDone() {
56
    return state == DecisionState.COMPLETED
1✔
57
        || state == DecisionState.COMPLETED_AFTER_CANCELLATION_DECISION_SENT;
58
  }
59

60
  @Override
61
  public void handleDecisionTaskStartedEvent() {
62
    switch (state) {
1✔
63
      case CREATED:
64
        stateHistory.add("handleDecisionTaskStartedEvent");
1✔
65
        state = DecisionState.DECISION_SENT;
1✔
66
        stateHistory.add(state.toString());
1✔
67
        break;
1✔
68
      default:
69
    }
70
  }
1✔
71

72
  @Override
73
  public boolean cancel(Runnable immediateCancellationCallback) {
74
    stateHistory.add("cancel");
1✔
75
    boolean result = false;
1✔
76
    switch (state) {
1✔
77
      case CREATED:
UNCOV
78
        state = DecisionState.COMPLETED;
×
UNCOV
79
        if (immediateCancellationCallback != null) {
×
UNCOV
80
          immediateCancellationCallback.run();
×
81
        }
82
        break;
83
      case DECISION_SENT:
84
        state = DecisionState.CANCELED_BEFORE_INITIATED;
×
85
        result = true;
×
86
        break;
×
87
      case INITIATED:
88
        state = DecisionState.CANCELED_AFTER_INITIATED;
1✔
89
        result = true;
1✔
90
        break;
1✔
91
      default:
92
        failStateTransition();
×
93
    }
94
    stateHistory.add(state.toString());
1✔
95
    return result;
1✔
96
  }
97

98
  @Override
99
  public void handleInitiatedEvent(HistoryEvent event) {
100
    stateHistory.add("handleInitiatedEvent");
1✔
101
    switch (state) {
1✔
102
      case DECISION_SENT:
103
        state = DecisionState.INITIATED;
1✔
104
        break;
1✔
105
      case CANCELED_BEFORE_INITIATED:
106
        state = DecisionState.CANCELED_AFTER_INITIATED;
×
107
        break;
×
108
      default:
109
        failStateTransition();
×
110
    }
111
    stateHistory.add(state.toString());
1✔
112
  }
1✔
113

114
  @Override
115
  public void handleInitiationFailedEvent(HistoryEvent event) {
116
    stateHistory.add("handleInitiationFailedEvent");
1✔
117
    switch (state) {
1✔
118
      case INITIATED:
119
      case DECISION_SENT:
120
      case CANCELED_BEFORE_INITIATED:
121
        state = DecisionState.COMPLETED;
1✔
122
        break;
1✔
123
      default:
124
        failStateTransition();
×
125
    }
126
    stateHistory.add(state.toString());
1✔
127
  }
1✔
128

129
  @Override
130
  public void handleStartedEvent(HistoryEvent event) {
131
    stateHistory.add("handleStartedEvent");
1✔
132
  }
1✔
133

134
  @Override
135
  public void handleCompletionEvent() {
136
    stateHistory.add("handleCompletionEvent");
1✔
137
    switch (state) {
1✔
138
      case CANCELED_AFTER_INITIATED:
139
      case INITIATED:
140
        state = DecisionState.COMPLETED;
1✔
141
        break;
1✔
142
      case CANCELLATION_DECISION_SENT:
143
        state = DecisionState.COMPLETED_AFTER_CANCELLATION_DECISION_SENT;
×
144
        break;
×
145
      default:
146
        failStateTransition();
×
147
    }
148
    stateHistory.add(state.toString());
1✔
149
  }
1✔
150

151
  @Override
152
  public void handleCancellationInitiatedEvent() {
153
    stateHistory.add("handleCancellationInitiatedEvent");
1✔
154
    switch (state) {
1✔
155
      case CANCELLATION_DECISION_SENT:
156
        // No state change
157
        break;
1✔
158
      default:
159
        failStateTransition();
×
160
    }
161
    stateHistory.add(state.toString());
1✔
162
  }
1✔
163

164
  @Override
165
  public void handleCancellationFailureEvent(HistoryEvent event) {
166
    stateHistory.add("handleCancellationFailureEvent");
×
167
    switch (state) {
×
168
      case COMPLETED_AFTER_CANCELLATION_DECISION_SENT:
169
        state = DecisionState.COMPLETED;
×
170
        break;
×
171
      default:
172
        failStateTransition();
×
173
    }
174
    stateHistory.add(state.toString());
×
175
  }
×
176

177
  @Override
178
  public void handleCancellationEvent() {
179
    stateHistory.add("handleCancellationEvent");
1✔
180
    switch (state) {
1✔
181
      case CANCELLATION_DECISION_SENT:
182
        state = DecisionState.COMPLETED;
1✔
183
        break;
1✔
184
      default:
185
        failStateTransition();
×
186
    }
187
    stateHistory.add(state.toString());
1✔
188
  }
1✔
189

190
  @Override
191
  public String toString() {
192
    return "DecisionStateMachineBase [id="
×
193
        + id
194
        + ", state="
195
        + state
196
        + ", isDone="
197
        + isDone()
×
198
        + ", stateHistory="
199
        + stateHistory
200
        + "]";
201
  }
202

203
  protected void failStateTransition() {
204
    throw new IllegalStateException("id=" + id + ", transitions=" + stateHistory);
×
205
  }
206
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc