# Buggy code
def kill_app_by_id(app_id):
    """Kill an application. If the app's state is FINISHED or FAILED, it won't be changed to KILLED.
    TODO: extend the yarn_api_client to support cluster_application_kill with PUT, e.g.:
        YarnProcessProxy.resource_mgr.cluster_application_kill(application_id=app_id)

    :param app_id
    :return: The JSON response of killing the application.
    """
    header = "Content-Type: application/json"
    data = '{"state": "KILLED"}'
    url = "%s/apps/%s/state" % (YarnProcessProxy.yarn_endpoint, app_id)
    cmd = ["curl", "-X", "PUT", "-H", header, "-d", data, url]
    process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    output, stderr = process.communicate()
    return json.loads(output) if output else None


# Traceback (OSError)
[D 2017-07-20 12:22:23.076 KernelGatewayApp] kernel_id=237badc9-ce85-42ea-bd13-4d8432993ca3, kernel_name=spark_2.1_scala_yarn_cluster, last_activity=2017-07-20 19:03:50.488255+00:00
[D 2017-07-20 12:22:23.077 KernelGatewayApp] kernel_id=d371a88a-53fb-42c9-827b-1ee263160716, kernel_name=spark_2.1_scala_yarn_cluster, last_activity=2017-07-20 18:56:10.546248+00:00
[E 170720 12:22:23 ioloop:638] Exception in callback <bound method IOLoopKernelRestarter.poll of <jupyter_client.ioloop.restarter.IOLoopKernelRestarter object at 0x7f15185a9210>>
Traceback (most recent call last):
File "/opt/anaconda2/lib/python2.7/site-packages/tornado/ioloop.py", line 1026, in _run
return self.callback()
File "/opt/anaconda2/lib/python2.7/site-packages/jupyter_client/restarter.py", line 88, in poll
if not self.kernel_manager.is_alive():
File "/opt/anaconda2/lib/python2.7/site-packages/jupyter_client/manager.py", line 433, in is_alive
if self.kernel.poll() is None:
File "/opt/anaconda2/lib/python2.7/site-packages/kernel_gateway/services/kernels/processproxy.py", line 440, in poll
state = YarnProcessProxy.query_app_state_by_id(self.application_id)
File "/opt/anaconda2/lib/python2.7/site-packages/kernel_gateway/services/kernels/processproxy.py", line 780, in query_app_state_by_id
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
File "/opt/anaconda2/lib/python2.7/subprocess.py", line 382, in __init__
errread, errwrite), to_close = self._get_handles(stdin, stdout, stderr)
File "/opt/anaconda2/lib/python2.7/subprocess.py", line 812, in _get_handles
c2pread, c2pwrite = self.pipe_cloexec()
File "/opt/anaconda2/lib/python2.7/subprocess.py", line 860, in pipe_cloexec
r, w = os.pipe()
OSError: [Errno 24] Too many open files
[E 170720 12:22:23 ioloop:638] Exception in callback <bound method IOLoopKernelRestarter.poll of <jupyter_client.ioloop.restarter.IOLoopKernelRestarter object at 0x7f1516a88a90>>
Traceback (most recent call last):
File "/opt/anaconda2/lib/python2.7/site-packages/tornado/ioloop.py", line 1026, in _run
return self.callback()
File "/opt/anaconda2/lib/python2.7/site-packages/jupyter_client/restarter.py", line 88, in poll
if not self.kernel_manager.is_alive():
File "/opt/anaconda2/lib/python2.7/site-packages/jupyter_client/manager.py", line 433, in is_alive
if self.kernel.poll() is None:
File "/opt/anaconda2/lib/python2.7/site-packages/kernel_gateway/services/kernels/processproxy.py", line 440, in poll
state = YarnProcessProxy.query_app_state_by_id(self.application_id)
File "/opt/anaconda2/lib/python2.7/site-packages/kernel_gateway/services/kernels/processproxy.py", line 780, in query_app_state_by_id
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
File "/opt/anaconda2/lib/python2.7/subprocess.py", line 382, in __init__
errread, errwrite), to_close = self._get_handles(stdin, stdout, stderr)
File "/opt/anaconda2/lib/python2.7/subprocess.py", line 812, in _get_handles
c2pread, c2pwrite = self.pipe_cloexec()
File "/opt/anaconda2/lib/python2.7/subprocess.py", line 860, in pipe_cloexec
r, w = os.pipe()

# Fixed code
def kill_app_by_id(app_id):
    """Kill an application. If the app's state is FINISHED or FAILED, it won't be changed to KILLED.
    TODO: extend the yarn_api_client to support cluster_application_kill with PUT, e.g.:
        YarnProcessProxy.resource_mgr.cluster_application_kill(application_id=app_id)

    :param app_id
    :return: The JSON response of killing the application.
    """
    header = "Content-Type: application/json"
    data = '{"state": "KILLED"}'
    url = "%s/apps/%s/state" % (YarnProcessProxy.yarn_endpoint, app_id)
    cmd = ["curl", "-X", "PUT", "-H", header, "-d", data, url]
    process = subprocess.Popen(
        cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True
    )
    output, stderr = process.communicate()
    return json.loads(output) if output else None