################################################################################
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
################################################################################
from abc import ABCMeta
from datetime import timedelta
from typing import Optional
from py4j.java_gateway import get_java_class
from pyflink.java_gateway import get_gateway
from pyflink.util.java_utils import to_j_flink_time, from_j_flink_time
__all__ = ['RestartStrategies', 'RestartStrategyConfiguration']
[docs]class RestartStrategyConfiguration(object, metaclass=ABCMeta):
"""
Abstract configuration for restart strategies.
"""
def __init__(self, j_restart_strategy_configuration):
self._j_restart_strategy_configuration = j_restart_strategy_configuration
def get_description(self) -> str:
"""
Returns a description which is shown in the web interface.
:return: Description of the restart strategy.
"""
return self._j_restart_strategy_configuration.getDescription()
def __eq__(self, other):
return isinstance(other, self.__class__) and \
self._j_restart_strategy_configuration == \
other._j_restart_strategy_configuration
def __hash__(self):
return self._j_restart_strategy_configuration.hashCode()
[docs]class RestartStrategies(object):
"""
This class defines methods to generate RestartStrategyConfigurations. These configurations are
used to create RestartStrategies at runtime.
The RestartStrategyConfigurations are used to decouple the core module from the runtime module.
"""
class NoRestartStrategyConfiguration(RestartStrategyConfiguration):
"""
Configuration representing no restart strategy.
"""
def __init__(self, j_restart_strategy=None):
if j_restart_strategy is None:
gateway = get_gateway()
self._j_restart_strategy_configuration = \
gateway.jvm.RestartStrategies.NoRestartStrategyConfiguration()
super(RestartStrategies.NoRestartStrategyConfiguration, self)\
.__init__(self._j_restart_strategy_configuration)
else:
super(RestartStrategies.NoRestartStrategyConfiguration, self) \
.__init__(j_restart_strategy)
class FixedDelayRestartStrategyConfiguration(RestartStrategyConfiguration):
"""
Configuration representing a fixed delay restart strategy.
"""
def __init__(self, restart_attempts=None, delay_between_attempts_interval=None,
j_restart_strategy=None):
if j_restart_strategy is None:
if not isinstance(delay_between_attempts_interval, (timedelta, int)):
raise TypeError("The delay_between_attempts_interval 'failure_interval' "
"only supports integer and datetime.timedelta, current input "
"type is %s." % type(delay_between_attempts_interval))
gateway = get_gateway()
self._j_restart_strategy_configuration = \
gateway.jvm.RestartStrategies\
.fixedDelayRestart(
restart_attempts, to_j_flink_time(delay_between_attempts_interval))
super(RestartStrategies.FixedDelayRestartStrategyConfiguration, self)\
.__init__(self._j_restart_strategy_configuration)
else:
super(RestartStrategies.FixedDelayRestartStrategyConfiguration, self) \
.__init__(j_restart_strategy)
def get_restart_attempts(self) -> int:
return self._j_restart_strategy_configuration.getRestartAttempts()
def get_delay_between_attempts_interval(self) -> timedelta:
return from_j_flink_time(
self._j_restart_strategy_configuration.getDelayBetweenAttemptsInterval())
class FailureRateRestartStrategyConfiguration(RestartStrategyConfiguration):
"""
Configuration representing a failure rate restart strategy.
"""
def __init__(self,
max_failure_rate=None,
failure_interval=None,
delay_between_attempts_interval=None,
j_restart_strategy=None):
if j_restart_strategy is None:
if not isinstance(failure_interval, (timedelta, int)):
raise TypeError("The parameter 'failure_interval' "
"only supports integer and datetime.timedelta, current input "
"type is %s." % type(failure_interval))
if not isinstance(delay_between_attempts_interval, (timedelta, int)):
raise TypeError("The delay_between_attempts_interval 'failure_interval' "
"only supports integer and datetime.timedelta, current input "
"type is %s." % type(delay_between_attempts_interval))
gateway = get_gateway()
self._j_restart_strategy_configuration = \
gateway.jvm.RestartStrategies\
.FailureRateRestartStrategyConfiguration(max_failure_rate,
to_j_flink_time(failure_interval),
to_j_flink_time(
delay_between_attempts_interval))
super(RestartStrategies.FailureRateRestartStrategyConfiguration, self)\
.__init__(self._j_restart_strategy_configuration)
else:
super(RestartStrategies.FailureRateRestartStrategyConfiguration, self)\
.__init__(j_restart_strategy)
def get_max_failure_rate(self) -> int:
return self._j_restart_strategy_configuration.getMaxFailureRate()
def get_failure_interval(self) -> timedelta:
return from_j_flink_time(self._j_restart_strategy_configuration.getFailureInterval())
def get_delay_between_attempts_interval(self) -> timedelta:
return from_j_flink_time(self._j_restart_strategy_configuration
.getDelayBetweenAttemptsInterval())
class FallbackRestartStrategyConfiguration(RestartStrategyConfiguration):
"""
Restart strategy configuration that could be used by jobs to use cluster level restart
strategy. Useful especially when one has a custom implementation of restart strategy set via
flink-conf.yaml.
"""
def __init__(self, j_restart_strategy=None):
if j_restart_strategy is None:
gateway = get_gateway()
self._j_restart_strategy_configuration = \
gateway.jvm.RestartStrategies.FallbackRestartStrategyConfiguration()
super(RestartStrategies.FallbackRestartStrategyConfiguration, self)\
.__init__(self._j_restart_strategy_configuration)
else:
super(RestartStrategies.FallbackRestartStrategyConfiguration, self)\
.__init__(j_restart_strategy)
@staticmethod
def _from_j_restart_strategy(j_restart_strategy) -> Optional[RestartStrategyConfiguration]:
if j_restart_strategy is None:
return None
gateway = get_gateway()
NoRestartStrategyConfiguration = gateway.jvm.RestartStrategies\
.NoRestartStrategyConfiguration
FixedDelayRestartStrategyConfiguration = gateway.jvm.RestartStrategies\
.FixedDelayRestartStrategyConfiguration
FailureRateRestartStrategyConfiguration = gateway.jvm.RestartStrategies\
.FailureRateRestartStrategyConfiguration
FallbackRestartStrategyConfiguration = gateway.jvm.RestartStrategies\
.FallbackRestartStrategyConfiguration
clz = j_restart_strategy.getClass()
if clz.getName() == get_java_class(NoRestartStrategyConfiguration).getName():
return RestartStrategies.NoRestartStrategyConfiguration(
j_restart_strategy=j_restart_strategy)
elif clz.getName() == get_java_class(FixedDelayRestartStrategyConfiguration).getName():
return RestartStrategies.FixedDelayRestartStrategyConfiguration(
j_restart_strategy=j_restart_strategy)
elif clz.getName() == get_java_class(FailureRateRestartStrategyConfiguration).getName():
return RestartStrategies.FailureRateRestartStrategyConfiguration(
j_restart_strategy=j_restart_strategy)
elif clz.getName() == get_java_class(FallbackRestartStrategyConfiguration).getName():
return RestartStrategies.FallbackRestartStrategyConfiguration(
j_restart_strategy=j_restart_strategy)
else:
raise Exception("Unsupported java RestartStrategyConfiguration: %s" % clz.getName())
@staticmethod
def no_restart() -> 'NoRestartStrategyConfiguration':
"""
Generates NoRestartStrategyConfiguration.
:return: The :class:`NoRestartStrategyConfiguration`.
"""
return RestartStrategies.NoRestartStrategyConfiguration()
@staticmethod
def fall_back_restart() -> 'FallbackRestartStrategyConfiguration':
return RestartStrategies.FallbackRestartStrategyConfiguration()
@staticmethod
def fixed_delay_restart(restart_attempts: int, delay_between_attempts: int) -> \
'FixedDelayRestartStrategyConfiguration':
"""
Generates a FixedDelayRestartStrategyConfiguration.
:param restart_attempts: Number of restart attempts for the FixedDelayRestartStrategy.
:param delay_between_attempts: Delay in-between restart attempts for the
FixedDelayRestartStrategy, the input could be integer value
in milliseconds or datetime.timedelta object.
:return: The :class:`FixedDelayRestartStrategyConfiguration`.
"""
return RestartStrategies.FixedDelayRestartStrategyConfiguration(restart_attempts,
delay_between_attempts)
@staticmethod
def failure_rate_restart(failure_rate: int, failure_interval: int, delay_interval: int) -> \
'FailureRateRestartStrategyConfiguration':
"""
Generates a FailureRateRestartStrategyConfiguration.
:param failure_rate: Maximum number of restarts in given interval ``failure_interval``
before failing a job.
:param failure_interval: Time interval for failures, the input could be integer value
in milliseconds or datetime.timedelta object.
:param delay_interval: Delay in-between restart attempts, the input could be integer value
in milliseconds or datetime.timedelta object.
"""
return RestartStrategies.FailureRateRestartStrategyConfiguration(failure_rate,
failure_interval,
delay_interval)