text:
fix(gio-badge): remove text-transform

Issue
N.A.
Description
In gio-badge, the text is transformed with capitalize. But this component is often used as a readonly viewer for gio-form-tags-input where no text transformation is applied.
To be more consistent, we remove the text transformation on gio-badge

Gravitee.io Automatic Deployment
A prerelease version of this package has been published! 🚀
To use it in your project run the following lines:
npm install @gravitee/ui-policy-studio-angular@2.9.0-fix-gio-badge-text-transform-542f263
# or
yarn add @gravitee/ui-policy-studio-angular@2.9.0-fix-gio-badge-text-transform-542f263

Gravitee.io Automatic Deployment
A prerelease version of this package has been published! 🚀
To use it in your project run the following lines:
npm install @gravitee/ui-particles-angular@2.9.0-fix-gio-badge-text-transform-542f263
# or
yarn add @gravitee/ui-particles-angular@2.9.0-fix-gio-badge-text-transform-542f263

Hi @loriepisicchio, I don't know if the badge is used in other cases, but if it is, it would be better to add a breaking change to force the next update by other projects to manually set text-transform. WDYT ?

@gcusnieux yep you're right I will change the commit message

Gravitee.io Automatic Deployment
A prerelease version of this package has been published! 🚀
To use it in your project run the following lines:
npm install @gravitee/ui-particles-angular@2.9.0-fix-gio-badge-text-transform-12f9446
# or
yarn add @gravitee/ui-particles-angular@2.9.0-fix-gio-badge-text-transform-12f9446

I'm not 💯  sure it's a good thing to remove this as it has been set after a discussion with the UI/UX team, to enforce consistency.
The use case you're describing makes me think of a simple mat-chip usage instead of tweaking the gio-badge
as they don't have the same height or icon handling for instance. Do you have some figma mockup showing this behavior?

Ok... it looks like from the latest components available in figma we don't want this behavior anymore 🙃

Don't know what to think as it's changing every month...

Oups, misclicked 🙈

@gaetanmaisse this has been discussed between @ibahloul and @audrey-tlm
Here is the corresponding mockup : https://www.figma.com/proto/sDRGgAlXUMcmy7RTRKEXbi/MVP_Cockpit?node-id=1763%3A6697&scaling=min-zoom&page-id=260%3A2419

authors: gaetanmaisse gcusnieux graviteeio loriepisicchio

repo: gravitee-io/gravitee-ui-particles


text:
feat: open modal for the whole page

Modal window state stretched to full page, no mardin, no border radius.  Useful on mobile.

@iapolya Hi, Modal is not supposed to be open in fullscreen by design. It has no "close" element except its overlay. So it won't be possible to close the Modal on mobile device in such scenario. There is a dedicated component for mobile cases - Sheet, which should be used instead

source: gharchive/pull-request

authors: amje iapolya

repo: gravity-ui/uikit

license: MIT

license_type: permissive

license_source: github-api


text:
Problem running PyBBIO ADC code on BBB attached to 4D Systems 4DCAPE

Alex:
I just now installed your PyBBIO and am having a problem with analogRead. My BBB is attached to a 4D_Systems 4DCAPE, and apparently that's causing the problem. Have a similar problem with Adafruit ADC code. Is the problem fixable? (BTW, PyBBIO PWM output works fine.)
http://www.4dsystems.com.au/product/4DCAPE_70T/
Traceback (most recent call last):
File "/var/lib/cloud9/ADC_Test.py", line 23, in
run(setup, loop)
File "/usr/local/lib/python2.7/dist-packages/bbio/bbio.py", line 60, in run
loop()
File "/var/lib/cloud9/ADC_Test.py", line 13, in loop
val1 = analogRead(pot1)
File "/usr/local/lib/python2.7/dist-packages/bbio/platform/beaglebone/adc.py", line 30, in analogRead
cape_manager.load(ADC_ENABLE_DTS_OVERLAY, auto_unload=False)
File "/usr/local/lib/python2.7/dist-packages/bbio/platform/beaglebone/cape_manager.py", line 27, in load
f.write(overlay)
IOError: [Errno 17] File exists
Here's my program:
Import PyBBIO library:
from bbio import *
pot1 = AIN4 # pin 33 on header P9
pot2 = AIN5 # pin 36 on header P9
def setup():
Nothing to do here
pass
def loop():
Get the ADC values:
val1 = analogRead(pot1)
val2 = analogRead(pot2)
And convert to voltages:
voltage1 = inVolts(val1)
voltage2 = inVolts(val2)
print " pot1 ADC value: %i - voltage: %fv" % (val1, voltage1)
print " pot2 ADC value: %i - voltage: %fv\n" % (val2, voltage2)
delay(500)
Start the loop:
run(setup, loop)
Thanks for your help.
John

I haven't used the 4D systems cape, but it looks like it's got a resistive touch screen and is using the ADC inputs AIN1, AIN2, AIN3 and AIN4 for that.
In theory it would be possible to get AIN5 and AIN6 working for general use, but that would require some Device Tree hacking, and maybe editing the DT overlay used by that cape. If you need the cape and some ADC inputs, it would probably be a lot easier to just use an external ADC. e.g. PyBBIO already has a library for the ADS786x series SPI ADCs.

Thanks Alex. Late last night after updating the Debian OS to from 3.8.13
bone47 to bone79, the PyBBIO ADC and PWM routines work 😊 but now the LCD
screen isn't showing the usual Debian stuff, only an arrow cursor that I
can move around. And also the Linux penguin shows briefly. So the LCD is ok
and I suppose there's some conflict between the PyBBIO software and the
screen software in the Debian distro. I'm hoping to get some answer from 4D
Systems about it or maybe from Robert Nelson of Debian.  So there may be
some hope to getting it all working. I'm getting pretty desperate because I
have to deliver some control systems soon and need both the PyBBIO and the
LCD working.
Thanks very much,
John
Sent from my iPhone
On Mar 16, 2016, at 8:28 AM, Alex Hiam notifications@github.com wrote:
I haven't used the 4D systems cape, but it looks like it's got a resistive
touch screen and is using the ADC inputs AIN1, AIN2, AIN3 and AIN4 for
that.
In theory it would be possible to get AIN5 and AIN6 working for general
use, but that would require some Device Tree hacking, and maybe editing the
DT overlay used by that cape. If you need the cape and some ADC inputs, it
would probably be a lot easier to just use an external ADC. e.g. PyBBIO
already has a library for the ADS786x
https://github.com/graycatlabs/PyBBIO/wiki/ADS786x series SPI ADCs.
—
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub
https://github.com/graycatlabs/PyBBIO/issues/98#issuecomment-197382733

Well that sounds like progress.
Unfortunately I doubt you'll get much support from 4D, considering the datasheet is wa outdated with only Angstrom instructions, and has this notice:

4D Systems does NOT support any software associated with the BBB nor software and drivers associated with this CAPE. It is up to the user to determine which software is used on the BBB and which distributions are used on the BBB, and therefore which are compatible with this CAPE.

:unamused:
You might be able to get some help on the #beagle irc channel (Robert is rcn-ee in there).

Yes, I'm pretty sure you're right about 4D and I do think Robert is a
good possibility for help. I emailed him but haven't heard back yet. And
I do like your idea about thanks again.the SPI ADC and DAC. I was hoping
not to have to do that, wanting to take advantage of the BBB's ADC and PWM.
Thanks again,
John
http://johnbakeree.blogspot.com/
On 3/16/2016 9:39 AM, Alex Hiam wrote:

Well that sounds like progress.
Unfortunately I doubt you'll get much support from 4D, considering the
datasheet is wa outdated with only Angstrom instructions, and has this
notice:
4D Systems does NOT support any software associated with the BBB
nor software and drivers associated with this CAPE. It is up to
the user to determine which software is used on the BBB and which
distributions are used on the BBB, and therefore which are
compatible with this CAPE.

:unamused:
You might be able to get some help on the #beagle irc channel (Robert
is rcn-ee in there).
—
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub
https://github.com/graycatlabs/PyBBIO/issues/98#issuecomment-197415773

Hi Alex:
I reverted to bone50 (Debian 3.8.13-bone50), reinstalled the PyBBIO
software and apparently both the PWM and ADC routines work. Perhaps I
had simply improperly installed bone79 or some other newbie problem. :-[
Thanks,
John
On 3/16/2016 9:39 AM, Alex Hiam wrote:

Well that sounds like progress.
Unfortunately I doubt you'll get much support from 4D, considering the
datasheet is wa outdated with only Angstrom instructions, and has this
notice:
4D Systems does NOT support any software associated with the BBB
nor software and drivers associated with this CAPE. It is up to
the user to determine which software is used on the BBB and which
distributions are used on the BBB, and therefore which are
compatible with this CAPE.

:unamused:
You might be able to get some help on the #beagle irc channel (Robert
is rcn-ee in there).
—
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub
https://github.com/graycatlabs/PyBBIO/issues/98#issuecomment-197415773

Weird, so the ADC is working along side the LCD and touchscreen?
It could be that the overlay the 4D cape is using changed after bone50. Since that overlay was made for different hardware and 4D offers zero software support, I wouldn't be surprised if it's just totally broken in more recent kernel versions :unamused:

Hi Alex,
I may have misspoken. With the Debian bone50, the LCD and both the software for the ADC and PWM are working fine. That all seems to be in good shape but unfortunately I can't run my Python program because one of the Tkinter routines isn't getting installed, TkAgg. TkAgg is required for my GUI and it had previously installed on the previous Debian, bone47, and except for the ADC and PWM everything had run so I should be able to install it on this Debian. Maybe a newbie goof. I will try bone79 again. I have been searching for a solution to the missing TkAgg. Others had reported the same problem but I haven't found the answer.
Regarding 4D, they don't provide any  software but strangely were recommending Android in their data sheet. I don't think Android has ever been used on the BBB, just originally Angstrom and now Debian and Ubuntu.
Anyhow it's all on me to get it running.
Fortunately your PyBBIO works great and I should be able to get it all operational.
Thanks for your help,
John
Sent from my iPhone

On Mar 18, 2016, at 8:26 AM, Alex Hiam notifications@github.com wrote:
Weird, so the ADC is working along side the LCD and touchscreen?
It could be that the overlay the 4D cape is using changed after bone50. Since that overlay was made for different hardware and 4D offers zero software support, I wouldn't be surprised if it's just totally broken in more recent kernel versions
—
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub

Alex:
I found a posting on the Beagleboard Forum that suggested connecting a
keyboard and mouse to the BBB in order to get a program running.
Surprisingly this worked and my Python matplotlib tkinter PyBBIO GUI
program is now working. Just a few more details. Don't know why the
keyboard and mouse are required but I'm planning on making my program
startup on reboot, so won't need the keyboard and mouse in the final
systems. That's a detail to be worked out.
Thanks for your help,
John
On 3/16/2016 9:39 AM, Alex Hiam wrote:

Well that sounds like progress.
Unfortunately I doubt you'll get much support from 4D, considering the
datasheet is wa outdated with only Angstrom instructions, and has this
notice:
4D Systems does NOT support any software associated with the BBB
nor software and drivers associated with this CAPE. It is up to
the user to determine which software is used on the BBB and which
distributions are used on the BBB, and therefore which are
compatible with this CAPE.

:unamused:
You might be able to get some help on the #beagle irc channel (Robert
is rcn-ee in there).
—
You are receiving this because you authored the thread.
Reply to this email directly or view it on GitHub
https://github.com/graycatlabs/PyBBIO/issues/98#issuecomment-197415773

source: gharchive/issue

authors: akerbay alexanderhiam

repo: graycatlabs/PyBBIO

license: mit

license_source: bigquery


text:
Add support for setting DelaySeconds for a Message

See #34

Not sure on how to fix the broken tests. Directions welcome :-).

Within the file SqsAdapterTest.php testEnqueue method it expects some calls to metadata-get with MessageAttributes.
This method should also include mocks for calls to 'DelaySeconds'.
$this->messageA->shouldRecieve('getMetadata->get')->once()->with('DelaySeconds')->andReturn(0);

and the sendMessageBatch method should have entries for the DelaySeconds property:
['Id' => 0, 'MessageBody' => 'foo', 'MessageAttributes' => [], 'DelaySeconds' => 0],

Also there should be tests to ensure the DelaySettings functionally is actually working.

If DelaySeconds is set in the message metadata we expect to see if being passed to sendMessageBatch

We will also need to consider what the default behaviour here should be and write some specific tests for those.

If DelaySeconds is set in the options and not set on a Message what is the expected behaviour? DelaySeconds should either not be there or should be the same as the options setting
If DelaySeconds is not set at all and not set in options? Either delay seconds should not be passed to the sendMessageBatch method or be set to 0.

Does that make sense?
If you would like me to write some of these tests let me know.

@h-bragg Spend a good hour or so trying to fix these tests, but Mockery keeps throwing exceptions at me which do not make a lot of sense to me. If you would like to add the tests: go for it. :-)

@bjornpost I created a new branch (and PR) #36 which the tests.
The tricky mockery exceptions are due to it not showing all of the differences between expected and actual arguments for method calls it is expecting.

Closing this in favor of #36

authors: bjornpost h-bragg

repo: graze/queue


text:
gateware.usb.usb2.descriptor: iCE40 Timings fixes

Re-timed the send handling code to improve timings on the iCE40 as using ULPI was failing before, this makes it pass at 71.56MHz on current yosys+nextpnr master

Thanks!

authors: DX-MON miek

repo: greatscottgadgets/luna


text:
Adds an opt-in border to all tabs irrespective of whether its the active tab or not

This preserves the same tab border style from the pre-2.0.0 UI. Only the active tab will have the full border, while all the other tabs will not show the border all around.
Older UI (ie with the opt-in boolean config either missing or false):

Newer UI (with the opt-in boolean config set to true)

Sorry - wrong parent branch. Will create a new PR against dev

repo: greeeen-dev/natsumi-browser


text:
Use https in package.json and update link in README.md

:gift:

brilliant, thanks! :)

:raising_hand: Wondering where in the code to update the reference in the commit message:

@JuanitoFatas That's in the private part of the project. I'll update it right away. Thanks again :+1:

@JuanitoFatas That's in the private part of the project. I'll update it right away. Thanks again

I was also amazed so less code to achieve all these. This explains :smile:

authors: JuanitoFatas boennemann janl

repo: greenkeeperio/greenkeeper


text:
Case sensitive imports in re-export file

🐛 Bug Report
Input file: add_chart.svg, addchart.svg (2 files)
Output Components: AddChart.js (1 file)
But re-export index.js file contains entries for both files.
export { default as AddChart } from './AddChart'
export { default as Addchart } from './Addchart'

This causes module not found an error in webpack with case sensitive plugin enabled.
Module not found: Error: [CaseSensitivePathsPlugin]
../Addchart.js` does not match the corresponding path on disk `AddChart.js`.

Expected behaviour:
index.js file should not have an entry for a component which doesn't exist in the folder.

I resolved the issue using a custom index template.
function defaultIndexTemplate(filePaths) {
    const filePathInLowerCase = filePaths.map(filePath => filePath.toLowerCase());
    const uniqueFilePaths = filePaths.filter((filePath, index) => {
        return filePathInLowerCase.indexOf(filePath.toLowerCase()) === index
    })

    const exportEntries = uniqueFilePaths.map((filePath) => {
    ...

Keeping it open for default solution.

Hello @ankitchouhan1020, I think it is an edge case. The problem is that you have "add_chart.svg" and "addchart.svg"... I will not handle this in SVGR, you should cleanup your input files.

repo: gregberge/svgr


text:
aggregated CPU and memory usage of a process and all of its children processes.

Hi,
would this script give the aggregated CPU and memory usage of a process and all of its children?
Thanks
Shuja

Not directly, but you can process the log data to get such a summary. Perhaps you can provide a patch for the R script for this ;)

authors: gregorgorjanc shujamughal

repo: gregorgorjanc/cpumemlog


text:
Update for GRF 2.0

Closes #67

@susanathey and @swager: the policytree replication code for your "Offline Multi-Action Policy Learning: Generalization and Optimization" is updated for GRF 2.0 in this commit.
The "one vs all" replication is here: https://github.com/grf-labs/policytree/blob/master/experiments/zhou_athey_wager_2018/check_replication_mapl.R
The "MGRF" replication is here: https://github.com/grf-labs/policytree/blob/master/experiments/zhou_athey_wager_2018/check_replication_mapl_v1.1.R

repo: grf-labs/policytree


text:
Error Message on Start

Every time I attempt to start the client I receive an error message about 'src/kernel.cp'. I have tried disabling antivirus software and 'upgraded' the software. I have tried repairing and uninstalling and reinstalling the client and nothing seems to work.

Hitting any option-abort, retry, or ignore-results in no change in result.

I believe this is caused by a corrupt blockchain.
Navigate to your appdata folder : %APPDATA%/roaming/gridcoinresearch/ backup wallet.dat walletbackup and gridcoinresearch.conf files.
Check that the gridcoinresearch.conf file isn't corrupt, if it is clean it up and launch the client again.
If the conf file wasn't at fault, delete all the files in the gridcoinresearch appdata folder (after having taken backups of the above mentioned files). Once deleted, reintroduce the backed up files to the folder and launch the client again.

authors: Nick-Katchur grctest

repo: gridcoin/Gridcoin-Research


text:
Relative image paths

Sorry but I'm completely confused by how Gridsome handles relative image paths.
Right now, the  frontmatter in my markdown is image: /media/image.jpg, and the media directory exists at the root of my project.
<div v-for="{ node } in $static.allOrganization.edges" class="sponsor__item" :key="node.id">
  <g-image :src="node.logo" :alt="node.name" />
</div>

The expected values ends up in the resulting image tag, but the problem is that /media/image.jpg doesn't exist.
How do I get Gridsome to point to this? Alternatively, can I get g-image to modify the the image path and point to the location instead?

Try
:src="`~/..${node.logo}`"

Your current file path isn't absolute so having it start with / is breaking
it.

@freshyill When using absolute paths, Gridsome will look for a file located somewhere in the /static folder. So moving the /media folder to /static/media should make your images work. But keep in mind that images in the /static folder are not processed in any way, just copied to the /dist folder when building for production.
You can use relative paths like image: ./image.jpg to process them with the built-in image processor. The image path must be relative to the Markdown file referencing it.

Also have the same question.
I have to reference some images placed in the static folder, so I can also use the same paths to them in meta tags using vue-meta (Would love to know if there was a better way around this). How can I get Gridsome to process these files?

I am also struggling to pass image paths from markdown front-matter through the g-image component. I have the images I need in a folder with the markdown files. I want to have two image paths in my front-matter:
heroImg: ./images/path-to-file
listingImg: ./images/path-to-file
Then in my projectListing.vue component (inside a loop) I want to have
<g-image
    :src="project.node.listingImg"
    :alt="project.node.listingImgAlt"
/>

And in my Project.vue file, I call bits of front-matter into a hero section before pulling in the markdown content underneath. That hero section has an image too:
<g-image :src="$page.project.heroImg" :alt="$page.project.heroImgAlt" class="hero-img"/>
Does anyone know what path I could use to get the images from my Projects folder? I really don't want to spend time optimising them myself and leaving them in the static folder, but that's the only way I can get it to work at the moment.
Please help!

I have a similar setup. Gridsome does not recognize the url provided by graphql as image object while processing. I have no idea how to fix it, and I'm getting frustrated by it. I'm using netlify CMS btw.

Looking in the repositories of some starters, the only way I found to solve this was by adding the parameter resolveAbsolutePaths: true from the plugin source-filesystem (gridsome.config.js file)
module.exports = {
  ...
  plugins: [
      {
        use: '@gridsome/source-filesystem',
        options: {
          path: 'blog/**/*.md',
          typeName: 'Post',
          resolveAbsolutePaths: true,
        },
      },
    ],
}

I put the thumbnails of my posts in the /uploads folder at the root of the project, I'm not sure if the g-image optimizations apply for these images (since it's outside of / src), but at least it works.

Looking in the repositories of some starters, the only way I found to solve this was by adding the parameter resolveAbsolutePaths: true from the plugin source-filesystem (gridsome.config.js file)
module.exports = {
  ...
  plugins: [
      {
        use: '@gridsome/source-filesystem',
        options: {
          path: 'blog/**/*.md',
          typeName: 'Post',
          resolveAbsolutePaths: true,
        },
      },
    ],
}

I put the thumbnails of my posts in the /uploads folder at the root of the project, I'm not sure if the g-image optimizations apply for these images (since it's outside of / src), but at least it works.

@alfosforo is there any documentation anywhere on the resolveAbsolutePaths option? I can't even find it in the source-filesystem source code!
And when I try adding it, my pages break:
[Vue warn]: Error in render: "TypeError: _vm.$page is null"

@alfosforo is there any documentation anywhere on the resolveAbsolutePaths option? I can't even find it in the source-filesystem source code!
And when I try adding it, my pages break:
[Vue warn]: Error in render: "TypeError: _vm.$page is null"

@NickSto seems that resolveAbsolutePaths is not defined on source-filesystem but in /node_modules/gridsome/lib/store/PluginStore.js
That's why you cannot find it in the source code nor the documentation.

authors: MrMacStripe NickSto RehanSaeed alfosforo freshyill hjvedvik jornhymcfly u12206050

repo: gridsome/gridsome


text:
[Meta] Communication and Discord

So, right now the "recommended" way of real-time chat/communication for this project seems to be Gitter. Sure, it's easily integrated with GitHub, but... It's a rather heavy application (especially on mobile where it seems to have even input lag), and honestly not that much used by people.
What I would recommend is to use Discord. With numerous bots available for this, GitHub integration should be smooth and painless, and will allow for much better real-time communication experience rather than Gitter.

This would be good once there are many contributors, but that's not the case right now.
Right now there are three main contributors (kramer, mechmind, and shelltitan) and they seem to have found something that works for them.
As it stands, there is a lot of dirt being kicked up by people who haven't contributed to the project (myself included), so Discord would only serve to make it easier to waste time theorizing with no real work being done.

Gitter have a IRC integration

I don't really have much time to sit in chats to argue about stuff.
When something is explained in Github issue it can be pointed out later from other issue - so I can reuse my explanations.
Chats tend to make discussions more hidden. Github issues is more opensource way in my opinion.

So I don't want to encourage people to use some chat. Gitter is kinda fine for small questions, and I don't think something bigger is needed.
However, I cannot forbid people to make any chat they want.

authors: Lourens-Rich dangranos kremius tuesdayMarch

repo: griefly/griefly


text:
Drawing a circle show a ellipse when draw the circle in a image target and blit it to another target

~/sdl-gpu/tests/render-target/main.c:
#include "SDL.h"
#include "SDL_gpu.h"
#include <math.h>
#include "compat.h"
#include "common.h"
#include "demo-font.h"

int main(int argc, char* argv[])
{
	GPU_Target* screen;

	screen = initialize_demo(argc, argv, 800, 600);
	if(screen == NULL)
		return 1;

	{
		GPU_Image* image2;
		GPU_Image* image3;
		SDL_Surface* font_surface;
		DemoFont* font;
		GPU_Image* mode1image;
		GPU_Image* mode2image;
		SDL_Color circleColor = { 255, 0, 0, 128 };
		SDL_Color circleColor2 = { 0, 0, 255, 128 };
		Uint32 startTime;
		long frameCount;
		const Uint8* keystates;
		int mode;
		int x;
		int y;
		Uint8 done;
		SDL_Event event;

		image2 = GPU_LoadImage("data/test2.bmp");
		if (image2 == NULL)
			return 2;

		image3 = GPU_LoadImage("data/test.bmp");
		if (image3 == NULL)
			return 3;

		font_surface = GPU_LoadSurface("data/comic14.png");
		font = FONT_Alloc(font_surface);
		if(font == NULL)
        {
            GPU_LogError("Failed to load font.\n");
            return 4;
        }
		GPU_SetRGB(font->image, 255, 0, 0);
		SDL_FreeSurface(font_surface);

		mode1image = GPU_CreateImage(300, 300, GPU_FORMAT_RGBA);
		if (mode1image == NULL)
			return 5;

		mode2image = GPU_CreateImage(400, 400, GPU_FORMAT_RGBA);
		if (mode2image == NULL)
			return 6;

		GPU_LoadTarget(mode1image);
		GPU_LoadTarget(mode2image);

        int height = 400;
		GPU_Image* light = GPU_CreateImage(height, height, GPU_FORMAT_RGBA);
        GPU_SetBlending(light, true);
		GPU_LoadTarget(light);
        GPU_ClearRGBA(light->target, 0, 0, 0, 128);

        float centerX = height / 2.0f;
        float centerY = height / 2.0f;
        float radius = height/ 2.0f;
        SDL_Color color = {255,255,0, 128};
        GPU_CircleFilled(light->target, centerX, centerY, radius, color);

		startTime = SDL_GetTicks();
		frameCount = 0;

		keystates = SDL_GetKeyState(NULL);

		mode = 0;
		x = 0;
		y = 0;

		done = 0;
		while (!done)
		{
			while (SDL_PollEvent(&event))
			{
				if (event.type == SDL_QUIT)
					done = 1;
				else if (event.type == SDL_KEYDOWN)
				{
					if (event.key.keysym.sym == SDLK_ESCAPE)
						done = 1;
					else if (event.key.keysym.sym == SDLK_SPACE)
					{
						mode++;
						if (mode > 1)
							mode = 0;
					}
					else if (event.key.keysym.sym == SDLK_f)
						GPU_SetFullscreen(!GPU_GetFullscreen(), 0);
					else if (event.key.keysym.sym == SDLK_g)
						GPU_SetFullscreen(!GPU_GetFullscreen(), 1);
					else if (event.key.keysym.sym == SDLK_1)
						GPU_UnsetVirtualResolution(screen);
					else if (event.key.keysym.sym == SDLK_2)
						GPU_SetVirtualResolution(screen, 1200, 800);
				}
			}

			if (keystates[KEY_UP])
				y -= 1;
			else if (keystates[KEY_DOWN])
				y += 1;
			if (keystates[KEY_LEFT])
				x -= 1;
			else if (keystates[KEY_RIGHT])
				x += 1;

			GPU_Clear(screen);

			if (mode == 0)
			{
				GPU_Target* mode1target = mode1image->target;
				SDL_Color red = { 255, 0, 0, 255 };

				GPU_ClearRGBA(mode1target, 0, 255, 0, 255);
				GPU_Blit(image3, NULL, mode1target, image3->w / 2, image3->h / 2);

				//GPU_BlitScale(image2, NULL, mode1target, mode1target->w/2, mode1target->h/2, 0.7f, 0.7f);
				//GPU_BlitScale(image2, NULL, mode1target, x, y, 0.7f, 0.7f);

				GPU_BlitTransform(image2, NULL, mode1target, x, y, 360 * sin(SDL_GetTicks() / 1000.0f), 0.7f*sin(SDL_GetTicks() / 2000.0f), 0.7f*sin(SDL_GetTicks() / 2000.0f));

				//GPU_Line(mode1target, 0, 0, mode1target->w, mode1target->h, red);
				//GPU_CircleFilled(mode1target, 70, 70, 20, circleColor);

                GPU_Rect srcRect = GPU_MakeRect(0, 0, light->w, light->h);
                GPU_Rect destRect = GPU_MakeRect(0, 0, light->w, light->h);
                GPU_BlitRect(light, &srcRect, mode1target, &destRect);

				GPU_Blit(mode1image, NULL, screen, mode1image->w / 2 + 50, mode1image->h / 2 + 50);
				GPU_BlitScale(mode1image, NULL, screen, mode1image->w * 2 + 50, mode1image->h / 2 + 50, 0.7f, 0.7f);

				GPU_CircleFilled(screen, 50 + 70, 50 + 70, 20, circleColor2);

				GPU_Blit(image2, NULL, screen, screen->w - image3->w - image2->w / 2, screen->h - image2->h / 2);
				GPU_Blit(image3, NULL, screen, screen->w - image3->w / 2, screen->h - image3->h / 2);
			}
			else if (mode == 1)
			{
				GPU_Target* mode2target = mode2image->target;
				SDL_Color red = { 255, 0, 0, 255 };
				SDL_Color blue = { 0, 0, 255, 255 };

				GPU_ClearRGBA(mode2target, 255, 255, 255, 255);

				GPU_Line(mode2target, 0, 0, mode2target->w, mode2target->h, red);
				GPU_Line(mode2target, 0, mode2target->h, mode2target->w, 0, red);
				GPU_TriFilled(mode2target, mode2target->w / 2, mode2target->h / 2 + 10, mode2target->w / 2 - 10, mode2target->h / 2 + 20, mode2target->w / 2 + 10, mode2target->h / 2 + 20, red);

				GPU_Blit(image2, NULL, mode2target, x, y);

				GPU_Line(screen, 0, 0, screen->w, screen->h, blue);
				GPU_Line(screen, 0, screen->h, screen->w, 0, blue);

				GPU_Blit(mode2image, NULL, screen, mode2image->w / 2, mode2image->h / 2);
			}

			FONT_Draw(font, screen, 20, 20, "Testing");

			GPU_Flip(screen);

			frameCount++;
			if (frameCount % 500 == 0)
			{
				printf("Average FPS: %.2f\n", 1000.0f*frameCount / (SDL_GetTicks() - startTime));
				printf("x,y: (%d, %d)\n", x, y);
			}
		}

		printf("Average FPS: %.2f\n", 1000.0f*frameCount / (SDL_GetTicks() - startTime));

		FONT_Free(font);
		GPU_FreeImage(mode2image);
		GPU_FreeImage(mode1image);
	}

	GPU_Quit();

	return 0;
}

@grimfang4
I have a feature: Generate some light textures  of different sizes with GPU_CircleFilled, and Blit the light texture of a size to screen.
But the shape and size  of the circle show incorrectly, it changes to a ellipse.
Could you please take a look?

And another simple code to describe the problem:
        {
            int width = 384;
            int height = 384;

            GPU_Image* light = GPU_CreateImage(width, height, GPU_FORMAT_RGBA);
            GPU_SetBlending(light, true);
            GPU_LoadTarget(light);

            GPU_ClearRGBA(light->target, 255, 0, 0, 128);

            float centerX = height / 2.0f;
            float centerY = height / 2.0f;
            float radius = height/ 2.0f;
            SDL_Color color = {255,255,0,128};

            GPU_CircleFilled(light->target, 0, 0, radius, color);

            GPU_SaveImage(light, "./light_3.png", GPU_FILE_AUTO);
        }

Generates:

Coordinates is wrong, (0,0) goes to bottom left.
Circle is not circle, it shows a Ellipse
Circle's size is wrong.
Please help.

Make the image width and height as the same as screen's width and height can fix the problem.

This looks like another issue from switching how the camera matrix is applied.  Thanks for the detailed report.

@grimfang4 My pleasure~ :D


text:
window sizing and file names

Some feedback from someone who used the app:

It does not open to the same size at which it closed, so has the be resized each time if user needs that.
The hack around file names (they are random and can't be moved) is annoying.

Auto-resizing window on startup is not natively supported by Electron, so we have to handle storing/reading the window size on our own. A sample implementation using electron-store: https://github.com/electron/electron/issues/526#issuecomment-1375534548
These could be a part of the bigger plan to refresh Grist Desktop's UX.
File renames:

authors: SleepyLeslie paulfitz

repo: gristlabs/grist-desktop


text:
Django update

Updated to min supported django version.

@sramirezgroveco Could you pls take a look ?

@sramirezgroveco It won't affect our site, since we have the requirements pinned to specific version. And it will not affect us since we're already on django 2.2

repo: groveco/django-sql-explorer


text:
Release 0.22.2

Technically there are breaking changes in this patch release due to #160, however in practice it seems unlikely that it will cause problems for downstream crates. We'd prefer to release this as a patch release to avoid some dependency churn downstream (especially across gfx/wgpu/wgpu-rs).
If this does turn out to cause problems for other crates downstream, we can always yank this release and bump the minor version instead.

bors r+

cc @kvark


text:
Feature Usage Callback

Other versions of the SDK seem to have a callback on feature usage (e.g. onFeatureUsage in the React SDK), but I didn't see an equivalent for the Kotlin SDK. Is this something that could be added?

We use onFeatureUsage in React Native to log analytics when useFeatureValue is called.

The pull request was created according to this issue.
After new release the usage will be like:

You can see the 'whether featureUsageCallback is called' test for more info.

authors: Bohdan-Kim szeidner

repo: growthbook/growthbook-kotlin


text:
The SDK should use a logging library

Currently the sdk uses standard out/error for logging (System.out en printStackTrace). It should use a library (slf4j tends to be the standard allowing the end user to provide the binding to the actual logging framework e.g. logback or log4j etc..) . I can provide a PR if there is an interest.

Hi @igorlovich thanks for offering to submit a PR for it. That would be great! Let's figure out the best approach.
We are trying to keep our dependencies to a minimum to keep our distribution size down. The SDK ships to Android as well, so adding to clients' bundle size is something we're trying to avoid if we can. If it can be done in a way that does not add additional dependencies and can be supported on Android, or the added dependencies are small, I think that would be acceptable.
I think it probably makes the most sense to have it added to the GBContext, as the last argument so that it's supported in the context builder. The SDK should not fail if a logger is not provided.
Is the slf4j library you're suggesting compatible with both Android and the JVM? If it's small and simple, I think we would be open to that change, e.g. if it's only a set of interfaces.
Did you want to discuss your suggested change first before getting started? Thanks.

Also, to follow up with the previous message, these are the example projects we'd test that logging works for:

https://github.com/growthbook/examples/tree/main/jvm-spring-web
https://github.com/growthbook/examples/tree/main/jvm-kotlin-ktor-example
https://github.com/growthbook/examples/tree/main/android-example

I understand your concerns and will try to address them one by one

The -api jar is mostly interfaces and the latest version is 62 kb in size.

The library does not do any logging as such; it is a facade (Slf4j = Simple Logging Facade for Java). By including the appropriate binding you can use whatever logging framework you want
e.g. slf4j-logback, slf4j-log4j etc.. etc..

For android logging there is slf4j-android binding, or if the project is using logback / log4j then one of the specific binding can  be used.

If no binding is provided  the logging operation is a no-op.

If the user wants to maintain the current behavior (i.e. printing to stdout/stderr) then they would need to provide sl4j-simple binding (12k in size)

Does this answer all your questions ?

Does this answer all your questions ?

@igorlovich yes! That seems like a good solution then, thanks for explaining it.
Feel free to proceed with that approach. Thanks again for offering!

@igorlovich thanks for the logging contribution. I've tested it out in some of the examples. My results are below.
The testing scenario is creating a GBFeaturesRepository that tries to decrypt an encrypted payload with a bad decryption key. This would result in an error log that should go via the logging setup you've set up.
✅  Spring
This is ok and appears to be working out-of-the-box. We see the error log.
🔴 Ktor
This is not working out-of-the-box. Ktor uses Logback. We get the following:
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.
SLF4J: Class path contains SLF4J bindings targeting slf4j-api versions 1.7.x or earlier.
SLF4J: Ignoring binding found at [jar:file:/..../.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-classic/1.2.11/4741689214e9d1e8408b206506cbe76d1c6a7d60/logback-classic-1.2.11.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See https://www.slf4j.org/codes.html#ignoredBindings for an explanation.

The output is not helpful and should log the error about a bad decryption key.
🔴 Java CLI
This is a new, plain app without any framework. The SDK needs to work in the simplest contexts in Java.
We get the following output which is not helpful to users. The example implementation should log the error logging related to a bad decryption key.
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.

🟡 Android
This is not yet tested. I wanted to see it working for the others first before adding it to Android, but if you are able to work with Android and add it, that would be great.
If not, we will need some guidance about how we can set this sort of thing up. The default logger in Android is Log, I'm not sure if that's slf4j-compatible. Perhaps a good example here is to have the user create their own logging class that implements slf4j and provide it to the GrowthBook SDK somehow. That latter part seems unclear and abstracted from us.

We will not be able to add your logging changes to the trunk until we are sure it's supported on all platforms we are supporting.
You can see the branch in the examples repo where I am adding the logging: https://github.com/growthbook/examples/compare/java-logging
Are you able to fork this branch and implement example logging classes for all the examples? It seems like the log field on all classes is private and final so a user cannot simply add a logger instance after the fact and must implement it another way, I'm guessing via annotations.
The suggestion I had made to add it to the constructor and allow a user to pass in their logging instance seems simpler to reason with. The Lombok annotations do seem like a faster implementation but they abstract the implementation.
We will need to be able to show working support for loggers in all our Java and Kotlin examples in order to merge it to main.
Let us know if you can help with these changes. Thanks!

Slf4j is NOT a logging framework (https://www.slf4j.org/manual.html). Like I have mentioned, the api dependency will not (and cannot) do any logging by itself. If you want "original" behavior in the examples, where things get printed out to stdout/stderr you need to include the implementation 'org.slf4j:slf4j-simple:2.0.7'
I just used lombok, because it was already used in the project (e.g. @Data, @Builder etc..). The annotation is equivalent to just writing
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SomeClass.class);
It does not really make sense to inject this through the context, as this field would and should never change. The whole point of the library is to abstract away the different logging frameworks behind a standard api.  You can't have users inject loggers as they all have different apis / signatures.

@igorlovich yes I'm aware slf4j does not provide logging and is a facade to be implemented. Did you miss the above examples? It works in only one of them out of the box (Spring) since they implement whatever needs to be implemented already, which means for the others, it will hide the current logging which may be helpful. Let us know if you can help with those examples? What do users who are unfamiliar with slf4j need to do in those other frameworks?

KTOR
The example uses logback as the logging framework (which implements the slf4j api directly). The logback version is too old (over a year) and should be upgraded to 1.4.7. But if you want to keep using it, we can downgrade the slf4j-api to 1.7.  The spring example works because spring boot version that you use 2.7.4 pulls in the 1.7 API jar already
CLI
This has no logging framework; and if you want to output to console
    implementation 'org.slf4j:slf4j-simple:$slf4j_version' dependency needs to be added
Android
I have no way to test this as I do not have an android env setup. But I don't see why this will not work given that the appropriate binding is included

Any update here @tinahollygb ?
Printing out to console is definitely something that should be avoided if possible, and the proposed solution is good :)

Hi @micpalmia thanks for the message. Was thinking about this issue from your PR message too. We haven't had a chance to tackle this as we have other priorities, but if you know Android development and how to work with slf4j there are a couple of outstanding tasks we need to do before we can be sure this will not introduce regressions in people's projects. You can see the details in this PR which implements this branch of work that @igorlovich has contributed. We want to get this added, but we need to be sure people's Android and framework-less projects will continue to work, and having example implementations that implement this so they can see the logging messages would be great. Is this something you want to help with? You can fork the branch in this project: https://github.com/growthbook/examples/pull/46
Essentially, we need to make sure for each of the examples:

it does not crash
users can see logging

Helo @tinahollygb, Do you have any predictions about this feature for the SDK?

Hi, we have created a pull request with a fix for this issue.

authors: igorlovich micpalmia mvsmasiero tinahollygb vazarkevych

repo: growthbook/growthbook-sdk-java


text:
Is Google CLA is needed once gRPC is owned by CNCF?

If not, CONTRIBUTING.md should be updated.

yes, we need to update to CNCF CLA and point to that in updated contribution guidelines.

Fixed:
https://github.com/grpc/grpc/blob/master/CONTRIBUTING.md
Remaining:
https://github.com/grpc/grpc-java/blob/master/CONTRIBUTING.md
https://github.com/grpc/grpc-go/blob/master/CONTRIBUTING.md

authors: jtattermusch zinuga

repo: grpc/grpc


text:
1.4: PHP gRPC extension causes fpm processes to hang, gets stuck in shutdown

What version of gRPC and what language are you using?
gRPC 1.4.0, PHP 7.0.18.
What operating system (Linux, Windows, …) and version?
Linux 4.9.0-0.bpo.2-amd64 #1 SMP Debian 4.9.18-1~bpo8+1 (2017-04-10) x86_64 GNU/Linux
What runtime / compiler are you using (e.g. python version or version of gcc)
gcc version 4.9.2 (Debian 4.9.2-10)
PHP 7.0.18-1~dotdeb+8.1 (cli) ( NTS )
What did you do?
Just installed PHP gRPC extension 1.4.0, proceeded as normal without utilizing any gRPC PHP code. Then ran on our integration server.
What did you expect to see?
PHP/FPM worker should normally shutdown.
What did you see instead?
FPM workers fail to shutdown properly, which eventually caused the FPM pool to max out its children, and eventually crash:
(gdb) bt
#0  pthread_cond_wait@@GLIBC_2.3.2 () at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S:185
#1  0x00007fa863ea1b9a in gpr_cv_wait () from /usr/lib/php/20151012/grpc.so
#2  0x00007fa863ecf0d3 in stop_threads () from /usr/lib/php/20151012/grpc.so
#3  0x00007fa863ecf132 in grpc_timer_manager_shutdown () from /usr/lib/php/20151012/grpc.so
#4  0x00007fa863ec1e98 in grpc_iomgr_shutdown () from /usr/lib/php/20151012/grpc.so
#5  0x00007fa863ea340b in grpc_shutdown () from /usr/lib/php/20151012/grpc.so
#6  0x00007fa863e9a3a7 in zm_shutdown_grpc () from /usr/lib/php/20151012/grpc.so
#7  0x000056471ab96207 in module_destructor (module=module@entry=0x56471c4110e0) at /usr/src/builddir/Zend/zend_API.c:2503
#8  0x000056471ab8e2cc in module_destructor_zval (zv=<optimized out>) at /usr/src/builddir/Zend/zend.c:620
#9  0x000056471aba1659 in _zend_hash_del_el_ex (prev=<optimized out>, p=<optimized out>, idx=<optimized out>, ht=<optimized out>) at /usr/src/builddir/Zend/zend_hash.c:1026
#10 _zend_hash_del_el (p=0x56471c4af220, idx=28, ht=0x56471b039d60 <module_registry>) at /usr/src/builddir/Zend/zend_hash.c:1050
#11 zend_hash_graceful_reverse_destroy (ht=ht@entry=0x56471b039d60 <module_registry>) at /usr/src/builddir/Zend/zend_hash.c:1506
#12 0x000056471ab9462c in zend_destroy_modules () at /usr/src/builddir/Zend/zend_API.c:1982
#13 0x000056471ab8f365 in zend_shutdown () at /usr/src/builddir/Zend/zend.c:856
#14 0x000056471ab2e79b in php_module_shutdown () at /usr/src/builddir/main/main.c:2360
#15 0x000056471aa13c85 in main (argc=475908082, argv=0x56471c5dc799) at /usr/src/builddir/sapi/fpm/fpm/fpm_main.c:2021

Anything else we should know about your project / environment?
No actual PHP code is being used; this is just with the extension loaded. Opcache is enabled.

same same...this killed a full day for me

Is this reproducible in earlier releases like 1.3.2?

Is this reproducible in earlier releases like 1.3.2?

We've just built a 1.3.2 , so should be able to confirm shortly (I work with @splittingred)

can confirm the problem doesn't exist in 1.3.2

@splittingred @chrisboulton Can you clarify a bit more about the error case? You mentioned the error happens during shutdown. I assume you have loaded the grpc extension via a php.ini for PHP/FPM? And during regular PHP script execution, is there no problem? The problem only happens when the FPM process shuts down? Is this only happening to your CI testing environment? I guess my question is: if this is production, will this happen during normal load when FPM is serving requests? Coz in production, I am assuming your FPM workers will, rarely, shutdown? Or my assumption is incorrect. Sorry for all these questions, I just want to clarify what we are dealing with here.

Happy to clarify -
In this case the shutdown handler/phase we're talking about is one that PHP is executing either at the end of every request, or (based on our configuration) one that occurs every X requests or Y seconds where FPM is actually recycling the workers. It's not the parent process shutting down, and it's not us explicitly triggering a shutdown.

or (based on our configuration) one that occurs every X requests or Y seconds where FPM is actually recycling the workers

Can you point me to a config snippet as to how to reproduce this with FPM?
Did you also mention that this can be reproduced even if the PHP requests/scripts don't use any gRPC code at all?
If this does not happen with version 1.3.2, then it may be related to #11005. We fixed a bunch of memory leaks and may have caused this.

Did you also mention that this can be reproduced even if the PHP requests/scripts don't use any gRPC code at all?

That is correct; we do not have the gRPC or protobuf composer packages loaded - just the grpc extension itself.

Can you point me to a config snippet as to how to reproduce this with FPM?

Sure. You essentially want to setup an FPM pool, and then configure the pm.max_requests option.
Note - I've not confirmed this is where the shutdown handler is kicking in for this case - it might just be after every request.
That said, I'd probably recommend setting up an FPM pool with one worker with a configuration something like the below and continually hitting it.

Did you also mention that this can be reproduced even if the PHP requests/scripts don't use any gRPC code at all?

Yep - you can see from the trace above that there's basically a generic shutdown handler in PHP that's iterating over any extension/module loaded into PHP and calling its destructor (in your case, zm_shutdown_grpc)

Two more clarifications:

So looks like triggering this shutdown procedure by FPM (every X requests or Y seconds) is normal? What's the advantage or that? Does this mean every PHP extension got completely wiped out and restarted in these child processes? (The reason I asked is that we are working on persisting the grpc channel across PHP requests to improve performance, i.e. for the life of the extension being loaded, we can re-use the underlying grpc channel. If extensions got reloaded frequently, then it kinda defeats the purpose).

Is reverting to 1.3.2, or not loading the grpc extension (since you are not using any grpc code) a workaround for now?

@stanley-cheung thank you for your responsiveness to this issue. It sounds like the gravity of the situation hasn't been adequately expressed.
This issue has bricked any system running FPM + gRPC. I can only speculate but i'm guessing this would touch millions of servers around the world.
So yes, downgrading to 1.3.2 is a workaround but it's very important you fix this issue. I'd imagine most people who have been hit by this simply don't know that your extension is the culprit. It was hard to identify as everything looks normal until all fpm workers lock-up.

Yes I do plan to fix this, especially if this is a regression from 1.3.2. I just haven't been able to reproduce this because I am somewhat unfamiliar with the FPM setup beyond the very basics.

OK, I'm pretty sure this is due to the PHP-FPM cycling processes - I spun up a DigitalOcean VM and was able to reproduce with a small static FPM pool configured with 2 processes and max 100 requests each.
ab -c 1 -n 1000 http://xxxx/i.php
This is ApacheBench, Version 2.3 <$Revision: 1757674 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking xxx (be patient)
Completed 100 requests
apr_pollset_poll: The timeout specified has expired (70007)

And PHP workers are stuck spinning:
root@debian-512mb-nyc3-01:~# gdb
(gdb) attach 18320
Attaching to process 18320
...
185	../sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S: No such file or directory.
(gdb) trace
Tracepoint 1 at 0x7fadf7b2c15f: file ../sysdeps/unix/sysv/linux/x86_64/pthread_cond_wait.S, line 185.

To reproduce, you want something like: (Debian Stretch, but any with PHP 7 should do)
apt-get update
apt-get install php7.0-dev php7.0-fpm zlib1g-dev # should pull down apache2 but if it doesn't, download and set it up too
a2enconf php7.0-fpm
a2disconf php7.0
pecl install grpc
echo 'extension=grpc.so' > /etc/php/7.0/mods-available/grpc.ini
echo <<EOF
[www]
user = www-data
group = www-data
listen = /run/php/php7.0-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = static
pm.max_children = 2
pm.max_requests = 50
EOF
echo '<?php phpinfo();' > /var/www/i.php
phpenmod -s ALL grpc
service apache2 restart
service php7.0-fpm restart

@stanley-cheung: More generally -

So looks like triggering this shutdown procedure by FPM (every X requests or Y seconds) is normal? What's the advantage or that? Does this mean every PHP extension got completely wiped out and restarted in these child processes? (The reason I asked is that we are working on persisting the grpc channel across PHP requests to improve performance, i.e. for the life of the extension being loaded, we can re-use the underlying grpc channel. If extensions got reloaded frequently, then it kinda defeats the purpose).

It's pretty normal in large setups, just to help avoid memory leaks, bad GC, etc. In our production environment we cycle FPM workers every 10k requests.
There's still a benefit to the persistent connection work you're doing and I think in our environment we'd benefit greatly, but you should really make sure you understand the PHP process models and the options available for sharing/maintaining a pool of persistent connections. Persistent connections got a bad wrap in the PHP community a while ago, but it's mostly because people don't understand how they work/interact with the process model they've chosen to run PHP under (ie which SAPI) and how to configure them accordingly. Happy to offer assistance in this area if you need it.

@chrisboulton Thanks for the repro test script. I will definitely look into this asap. Super helpful!

@chrisboulton Hi, I followed your steps above on a Debian Stretch instances with PHP 7.0.19. But apache is not executing the PHP code. Just giving me back the text of the i.php file. I guess I am missing a .conf somewhere under /etc/apache2?

hm looks like it completed 1000 requests?
stanleycheung@stanleycheung-debian9:~$ ab -c 1 -n 1000 localhost/i.php
This is ApacheBench, Version 2.3 <$Revision: 1757674 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests

Server Software:        Apache/2.4.25
Server Hostname:        localhost
Server Port:            80

Document Path:          /i.php
Document Length:        70213 bytes

Concurrency Level:      1
Time taken for tests:   0.954 seconds
Complete requests:      1000
Failed requests:        974
   (Connect: 0, Receive: 0, Length: 974, Exceptions: 0)
Total transferred:      70384779 bytes
HTML transferred:       70214779 bytes
Requests per second:    1047.71 [#/sec] (mean)
Time per request:       0.954 [ms] (mean)
Time per request:       0.954 [ms] (mean, across all concurrent requests)
Transfer rate:          72014.76 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:     1    1   0.5      1      14
Waiting:        1    1   0.3      1       4
Total:          1    1   0.5      1      14

Percentage of the requests served within a certain time (ms)
  50%      1
  66%      1
  75%      1
  80%      1
  90%      1
  95%      1
  98%      1
  99%      1
 100%     14 (longest request)

You don't want libapache2-mod-php in this circumstance - we were seeing the problem with FPM, not the Apache module SAPI.
It's possible I've missed something in my steps above which was resulting in PHP not working - give me 10 minutes to setup a new VM and find out what I've missed.

Yea I just realized I shouldn't be using libapache2-mod-php - it routes the .php files to another handler not FPM.
Thanks for the help!

I do have a /etc/apache2/conf-enabled/php7.0-fpm.conf that have this snippet
<IfModule !mod_php7.c>
<IfModule proxy_fcgi_module>
    # Enable http authorization headers
    <IfModule setenvif_module>
    SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
    </IfModule>

    <FilesMatch ".+\.ph(p[3457]?|t|tml)$">
        SetHandler "proxy:unix:/run/php/php7.0-fpm.sock|fcgi://localhost"
    </FilesMatch>

So it seems like it should work

I'd have a look to see if the fcgi is enabled... a2enmod proxy_fcgi

~$ sudo a2enmod proxy-fcgi
ERROR: Module proxy-fcgi does not exist!

Ah - do apt-get install libapache2-mod-fcgid

Just tried that and didn't seem to work
~$sudo apt-get install libapache2-mod-fcgid
Reading package lists... Done
Building dependency tree
Reading state information... Done
libapache2-mod-fcgid is already the newest version (1:2.3.9-1+b1).
0 upgraded, 0 newly installed, 0 to remove and 6 not upgraded.
stanleycheung@stanleycheung-debian9:~$ sudo service apache2 restart
stanleycheung@stanleycheung-debian9:~$ sudo service php7.0-fpm restart
stanleycheung@stanleycheung-debian9:~$ curl localhost/i.php
<?php

if (extension_loaded('grpc')) {
  print("grpc extension loaded\n");
} else {
  print("grpc extension not loaded\n");

Can you run through the above instructions again? Sorry - when I wrote them up it was after the fact and late at night. I've just gone through and updated some things. I think you're mainly missing the setenvif module at the moment.

Great! a2enmod proxy_fcgi entenvif did it. Now I am able see this:
~$ curl localhost/i.php
grpc extension loaded

And reproduced this:
~$ ab -c 1 -n 1000 localhost/i.php
This is ApacheBench, Version 2.3 <$Revision: 1757674 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
apr_pollset_poll: The timeout specified has expired (70007)
Total of 99 requests completed

Quick update: I reproduced this issue and narrowed it down to a particular new call introduced to the shutdown procedure recently. Working with the core team to understand the issue.

Summary of findings:

I traced it down to the fact that the grpc extension is loaded at the php-fpm parent process. In the PHP MINIT function, we call grpc_init. At 1.4 or later, the gRPC C core library introduced a new thread to manage timer related stuff. That thread was not forked into the php-fpm child processes.
So when the child php-fpm process is shutdown (i.e. when the PHP MSHUTDOWN function is called to shutdown each extension), the grpc_shutdown function hangs because the underlying grpc_timer_manager_shutdown cannot find the timer manager thread, which was at the parent process.
Unfortunately, grpc has not officially supported fork. Previously things work at version 1.3.2 or before was because it so happened that, if fork happens after grpc_init, and before any grpc channel is created, it will work but just accidentally. With this new timer manager change in 1.4, it will not work if fork happens after grpc_init.
The short term workaround is to use version 1.3.2. If there's any critical bug fixes, we can backport it there.
There is ongoing work in grpc core to support forking properly, but that will be 1 to 2 releases out.
This is another really ugly workaround is to simply not call grpc_shutdown at the PHP_MSHUTDOWN_FUNCTION. It may be acceptable if the child process is going away anyway but I don't know the memory leak implication if we do that. Plus, the timer manager thread will still be at the parent so I don't know whether deadline, cancel related functionality will still work.
This is the same issue as #11506

Questions for community:

Does anybody know if there's a way for the PHP extension to call a function after php-fpm forks the child process? If that's possible, I can make the change in our gRPC PHP extension to only call grpc_init at that hook, rather that at the PHP_MINIT_FUNCTION. I think RINIT is called per request which is too expensive. I tried GINIT but it doesn't seem to be called after forking.

Does anybody know if there's a way for the PHP extension to call a function after php-fpm forks the child process?

My immediate thought (without having dug through the FPM SAPI just yet), would be that you might need to implement this in RINIT, but implement some kind of short circuit if the library has already been initialized in the worker, to eliminate the expensive call.
I'll see if I can find some time in the next few days to dig through the SAPI code to see if there are any other better hooks.

@chrisboulton I made a PR #11814. If by any chance you can build and test this manually that would be great. Thanks for all the help debugging this issue so far.

Hi @chrisboulton  Did you by any chance get to review the PR?

Is it possible that the issue that's being discussed here also affects Apache (2.4 - mpm prefork) when using gRPC as PHP 7.1 module? When we're trying to reload (gracefully restart) Apache, all the active Apache workers switch to a 'Gracefully restarting' mode, where they don't come out of, unless I restart Apache. When I disable the GRPC module in PHP, this behaviour is solved. I can reproduce this at multiple machines. We're using gRPC 1.4.2 via PECL.

@rfeiner yes this would affect the Apache use case if child processes are forked after the extension was loaded in the parent process. This fix should help. Just to confirm, you mean the problem exists in 1.4.1 (there's no 1.4.2 yet) and not in 1.3.2 right?

@stanley-cheung, 1.4.1 indeed. We've downgraded to 1.3.2 and problem is over.

@rfeiner thanks for confirming. We are planning the fix for this for 1.4.2 (or whatever the next number is). Stay tuned.

To add more information, i just have the same problem with a CLI php process wich is stuck during exiting only when the grpc extension is enabled. Problem exist both with 7.0 & 7.1 php version.

@stanley-cheung Any update on this?

This is now fixed in 1.4.4

authors: bacheson chrisboulton mattolson rfeiner splittingred stanley-cheung wpottier


text:
PHP: disable cares for release 1.3

This is a temporary workaround to unblock the PHP 1.3 release
Fixes #10940
This will add a compiler flag -DGRPC_ARES=0 to the PHP extension to disable the cares dependency. Currently the PHP client has not implemented the associated functionality, similar to Node.
This will allow us to upload the PHP release to PECL.

Performance differences noted:
Benchmark                                                cpu_time    real_time
-----------------------------------------------------  ----------  -----------
BM_HpackParserParseHeader<AddIndexedSingleStaticElem>      -24.50       -24.50
BM_IsolatedFilter<ServerDeadlineFilter, NoOp>               +6.00        +6.00

#10539 #10888

authors: grpc-testing stanley-cheung